1.工厂模式
缺点:没有解决怎样知道一个对象类型的问题
2.构造函数模式
与工厂模式不同之处:
1.没有显示的创建对象
2.直接将属性和方法赋值给this
3.没有return语句
要创建Person
的实例,必须使用new
操作符,经历了以下四个步骤
1.创建了一个新对象
2.将构造函数的作用域赋给新对象(this就指向了这个对象)
3.执行构造函数中的代码(为这个对象添加属性和方法)
4.返回这个对象
存在的缺点:每个方法在每个实例上都要被重新创建一遍
eg.
var person1 = new Person("wxw", 18, "student");
var person2 = new Person("wxo", 48, "teacher");
person1
和 person2
都有一个sayName
的方法,但这个方法不是同一个function的实例。因为函数也是一个对象,所以在每定义一个函数时,就相当于实例化了一个对象。所以每个Person
实例都包含了一个不同Funcion
的实例(用来显示name
属性)。导致不同实例的同名函数是不相等的。
可以这么理解:this.sayName = new Function(){"alert(this.name)"}
;
改进方法:
切记:函数名是一个指向函数的指针!!!
缺点:
在全局作用域中定义的函数只能被某个对象调用
若有很多方法时,要定义很多个类似的全局函数,没有封装性。
3.原型模式
我们创建的每个函数都有prototype
属性,该属性是一个指针,指向一个对象。可以利用这个属性来定义由特定类型的所有实例所共享的属性和方法
来理解下原型对象
只要创建了一个新函数,就会为这函数创建一个prototype
属性,指向函数的原型对象。而每个原型对象都会自动获得一个constructor
(构造函数)属性,指向这个prototype属性所在的函数。即Person.prototype.constructor
当调用构造函数创建一个实例后,这个实例内部包含一个指针(proto),指向构造函数原型对象。与构造函数无关。
== Person; //true
缺点:
- 1.不能通过对象实例重写原型中的值
- 2.要重复写很多
Person.prototype
,麻烦 - 3.属性共享导致引用类型值的属性,被一个实例修改后,会影响所有实例的改引用类型值
为了解决2,提出了对象字面量的写法
注意,使用对象字面量的形式会创建一个新对象,所以就相当于为Person.prototype
赋给了一个新对象,导致,construct
属性不再指向Person了。
分析下上面那个例子。
使用对象字面量创建了一个对象(可以直接理解成创建了一个新函数),这个函数在创建的同时就会创建他的
prototype
属性,指向Object.prototype
,而这个Object.prottotype
也会自动获得constructor
属性,指向Object。所以,Person.prototype.constructor
导致通过
== Object; //true.constructor
属性已经无法确定对象的类型了。所以为了解决这个问题,需要显示指定constructor
的值。
修改后如下:
为了解决1,3缺点,提出
4. 组合使用构造函数模式和原型模式
5 动态原型模式
通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型
注意:在使用动态原型模式时,不能使用对象字面量重写原型。因为在已经创建实例的情况下重写原型,会切断现有实例与新原型之间的联系
6.寄生构造模式
基本思想:创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后返回新创建的对象
除了使用new
操作符并把使用的包装函数叫做构造函数外,这个模式跟工厂模式一模一样。
注意:返回的对象与构造函数或者与构造函数的原型属性之间没有任何关系
7.稳妥的构造函数模式
稳妥构造函数模式与寄生构造函数类似模式,但有两点不同:
1.新创建对象的实例方法不引用this
;
2.不使用new
操作符调用构造函数