1. 面向对象
- 对象两大特征:属性和方法;
- 面向对象(oop,oo)思想:
- 封装:对于同一个功能,只需要封装一次,以后再使用的时候,只需要调用即可,无需重写;这种叫做低耦合高内聚;
- 继承:子类可以继承父类的属性和方法;
- 多态:重载和重写;
- 重载:JS上没有严格意义上的重载;但有类似重载的功能,就是传不同的参数,有不同的返回值;
- 重写:子类可以重写父类的属性和方法;
2. 面向对象的设计模式:
- 列举四种常见的设计模式:
- 单例模式
- 工厂模式
- 构造函数模式
- 构造函数原型模式(原型模式)
2.1单例模式
- 把同一个对象上的属性和方法,都放在同一个内存空间中,给这个内存空间起个名字,这个名字就叫做命名空间;
- 单例模式的本质:普通对象;建立多个对象,添加属性和方法;
- 模块化开发:对于一个复杂的大项目,可以分配给不同的工程师同步进行开发;等项目完成的时候,合并即可;
- 各个模块之间的相互调用:对象名.属性名;
- 本模块之间的相互调用:this.属性名
<script>
var person1={
name:"zhangsan",
age:26
};
var person2={
name:"lisi",
age:person1.age,//不同对象之间的调用,用对象名.属性名获取属性值;
introduce:function () {
console.log("我的名字是"+this.name);//本对象中的调用,用this.属性名获取属性值;
}
};
console.log(person2.age);
person2.introduce();//加()进行函数执行;
</script>
2.2 工厂模式
- 工厂模式,分三步:1)创建对象 2)给对象添加属性和方法 3)返回对象;
- 实质:创建一个新的函数,添加形参,当调用函数的时候,传入实参,获得一个对象;
- 缺点:每调用一次函数,都会形成一个新的堆地址,内存容量会很大;
<script>
function person(name,age){
//1.引进原材料
var obj=new Object();//实例型创建对象;var obj={};为字面量型创建对象;
//2.加工原材料
obj.name=name;
obj.age=age;//给对象添加属性名及属性值;
obj.showName=function () {//将函数定义的地址赋给showName;
console.log("我的名字是"+this.name);
};//添加一个方法;
//3.输出原材料
return obj;
}
var person1=person("1111",18);//调用函数,传入实参;生成一个对象;
var person2=person("2222",19);
console.log(person1.showName===person2.showName);//判断两个对象在定义函数时的地址是否相同;结果为false;
</script>
2.3 构造函数模式
- 工厂模式转化为构建函数模式的步骤:
- 函数名首字母大写,形成类函数;
- 函数定义中删除创建空对象步骤,和返回对象步骤,默认进行这两步;添加属性及方法步骤中,obj变成this
- 调用函数时,添加new 函数名(实参);
- 工厂模式和构造函数模式的区别:
- 在调用的时候:
- 工厂模式:person();
- 构造函数模式:new Person();是一个类;
- 在函数体内:
- 工厂模式三步:1)创建对象 2)对象添加属性和方法 3)返回对象;
- 构造函数模式只有一步:对象添加属性和方法,第一步和第三步系统默认做了,系统提供了一个对象叫做this;
- 构造函数模式
- 构造函数首字母一定大写;
- 构造函数中放的都是私有的属性和方法;
- 原型上放的都是共有的属性和方法;
- 系统默认会创建一个对象,this;
- 系统默认会返回一个对象,this;
- 构造函数中的this,指向当前这个实例;(构造函数new给谁,this就指向谁);
- 构造函数中存放的都是私有的属性和方法;
- 构造函数是函数的定义阶段,里面的代码被作为字符串存在堆内存地址中;
- 原型是个对象,里面存在都是共有的属性和方法;
-
var f=new Fn()
:实例创建一定是对象,是对构造函数的调用;
function Person(name,age){//函数名首字母大写;
/* //1.引进原材料
var obj=new Object();//实例型创建对象;*/
//2.加工原材料
this.name=name;
this.age=age;
this.showName=function () {//将函数定义的地址赋给showName;
console.log("我的名字是"+this.name);
};//添加一个方法;
/* //3.输出原材料
return obj;*/
}
var person1=new Person("1111",18);//调用函数时,要添加new 函数名(实参);
var person2=new Person("2222",19);
console.log(person1.name);
console.log(person2.showName());//此时打印结果为undefined,因为函数没有返回值;
console.log(person1.showName===person2.showName);//判断两个对象在定义函数时的地址是否相同;结果为false;
2.4 构造函数原型模式(原型模式)
- 构造函数原型模式:在构造函数的基础上,创建一个公共的地址,每次调用函数时,不会创建更多的堆地址;
- 以下实例中:添加公共属性prototype
<script>
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.showName=function () {
console.log("我的名字是"+this.name);
};//添加公共地址,引用时全部调用此地址;
var person1=new Person("1111",18);//调用函数时,要添加new 函数名(实参);
var person2=new Person("2222",19);
console.log(person1.name);
console.log(person2.showName());//此时打印结果为undefined,因为函数没有返回值;
console.log(person1.showName===person2.showName);//判断两个对象在定义函数时的地址是否相同;结果为true;
</script>
- 四种模式的区别:
- 单例模式:每个对象的属性名,方法,全部定义一遍,非常麻烦;
- 工厂模式:同样的东西写一遍就行;创建一个函数,传入实参获得不同的对象,缺点:每调用一次函数,函数中的showName属性都会形成一个新的堆地址,内存容量会很大;
- 构造函数模式:将工厂模式中的函数精简,函数首字母大写,变成类函数,用实例型创建,即添加new 函数名(形参);缺点:跟工厂模式相同,会形成很多的地址;
- 构造函数原型模式(原型模式):在构造函数基础上添加公共地址,prototype;避免创建更多的堆地址;
2.5 面向对象的结果
- 面向对象的结果:就是创建一个类似于new Array()的数组类函数,里面有属性和原型模式,原型模式里面添加的是方法;
- 数组类new Array()分析:
<script>
var ary1=new Array(100,200);
var ary2=new Array(300,400);
ary1.push();//指的是ary1对象上的方法,即在ary1对象私有属性"_ _photo_ _"上不存在push()方法,要去它所属类Array上的prototype对象中寻找,得到push()方法;
console.dir(ary1);//dir打印变量身上的属性和方法;
console.dir(ary2);
console.log(ary1.constructor);//打印的是Array类,用于查找ary1属于哪个类函数;
</script>
- 数组类分析:
- 类函数Array
- Array为一个类函数,包含基本属性和prototype属性;
- 基本属性:
- 属性名为从0开始递增,通过new Array()中括号里传入实参,来进行赋值;
- 还有一个length属性,属性名为数组长度;
- prototype为一个对象,所以新建一个堆地址,里面存放键值对;然后将地址作为属性值赋给prototype;
- 在prototype堆地址中,有一组键值对,其中属性名为constructor,对应的属性值为当前所属类;
- 在prototype堆地址中,还有许多键值对,也可称为方法;如push(),pop()等,
- 方法的存在方式是键值对,属性名为push;对应的属性值为function(){};
- 使用方法时,代码ary.push()的意思是()();即调用函数执行;
- 类函数的实质:创建一个函数,返回一个对象;
- 对象
- 代码 var ary1= new Array(100,200);含义:类函数Array调用,传入实参100和200,执行完成后返回一个对象,赋给ary1;
- 调用函数时创建一个私有作用域,其中ary1对象中存在四组键值对
- 基本属性三组:分别是
0:100
,1:200
,length:2
- 第三组键值对:属性名为:
_ _proto_ _
;属性值为:指向当前对象所属类(Array)的原型(prototype);
- 通过
ary1.constructor
找到ary1所属的类函数;
- 模拟数组函数
<script>
function Ary() {
//基本属性的设置
for(var i=0;i<arguments.length; i++){
this[i]=arguments[i];
}
this.length=arguments.length;
}
//在公共地址中添加方法
Ary.prototype.push1=function (news) {
var num=this.length;//获元素长度
this[num]=news;//给对象添加属性num,给其赋值为news;
this.length=num+1;//设置函数内的length属性,使其属性值加1;
return this.length;//返回值,为新数组的长度
};
var ary111=new Ary(100,200,300,40,5,6);
/*console.dir(ary111);*/
var newscount=ary111.push1(30);//此时返回值为新数组的长度
console.dir(ary111);
console.log(newscount);
</script>
- 构造函数原型模式原型图
- 原型模式基础:
- 每个类函数数据类型,都有一个属性,叫做prototype,其中prototype是个对象,指向一个堆地址空间;
- prototype这个对象的堆地址空间中,存放的是键值对,其中,天生自带一个属性,叫做constructor,它的属性值指向当前所属类;
- 每个对象身上,都有一个属性,叫做_ proto _,它的属性值指向当前实例所属类的原型,即prototype对象Object;
- 原型链:指的是
_ _proto_ _
- 如果要查找—对象.属性名 比如f1.showX;
- 先在自己的私有作用域中查找;如果找到,那么这个属性就是私有属性;
- 如果没找到,到当前实例所属类的原型上找(f1._ proto _),如果找到属于共有的属性或方法;
- 如果还没找到,继续通过_ proto _往上找,一直找到Object.prototype上还没有的话,返回undefined;
- 注意:变量不存在则找不到会报错,而变量已声明但未定义返回undefined,属性找不到会返回undefined;
- 要形成的几个条件反射:
- 看到构造函数——存的是私有的属性和方法;
- 看到prototype——存的都是共有的属性和方法;
- _ proto _原型链;
- 数组对象中的私有属性及所属类,以及所属祖类