创建对象
工厂模式
使用Object函数和对象字面量的方式创建对象,都有一个巨大的缺点:使用同一接口创建多个对象时,会造成大量重复代码。
function createPerson(name){
var o=new Object();
o.name=name;
o.sayName=function(){
alter(this.name);
}
return o;
}
var person1=createPerson("jack");
var person2=createPerson("lucy");
但是工厂模式有一个问题,即无法判断该对象的类型。于是构造函数模式出现了。
构造函数模式
function Person(name){
this.name=name;
this.sayName=function(){
alter(this.name);
}
}
var person1=new Person("jack");
var person2=new Person("lucy");
构造函数与工厂模式相比,不需要在构造函数中显式创建对象和return 对象,并且使用new操作符来调用构造函数。使用构造函数的缺点是:每个对象的中的同名函数都要重新创建一个函数对象,即不同的对象的同名函数不相等。
alert(person1.sayName == person2.sayName); //false
原型模式
1,我们创建的每个函数都有一个prototype属性,这个属性是一个指针指向一个对象。原型对象中包含特定类型的所有实例共享的属性和方法。
function Person(){}
Person.prototype.name="jack";
Person.prototype.sayName=function(){
alter(this.name);
};
var person1=new Person();
var person2=new Person();
alert(person1.sayName == person2.sayName); //true
原型对象默认获得一个constructor属性,指向prototype所在函数。所有通过构造函数创建出来的对象内部都具有一个指针[[prototype]],指向构造函数的原型对象。需要注意的是:对象中的[[prototype]]指向原型,而不指向构造函数。所以person1和person2与构造函数没有多大的关系。
每当代码读取某个对象的某个属性时,会先在对象的内部查找是否存在,若不存在,会去对象所指向的原型对象查找。
使用对象字面量的方式来为原先对象中添加或修改属性本质上是完全重写了默认的prototype对象。使用这种方法来创建prototype对象会使得它的constructor对象指向Object构造函数。所以需要手动的将construtor属性指向原来对象。重写原型对象切断了现有原型与任何之前以及存在的对象实例之间的联系,它们引用的仍然是最初的原型。
原生引用类型同样在原型对象中定义一些方法,例如Array来原型中定义了sort方法。
2,原型模式缺点
所有的对象共享着所有的属性和方法,当一个属性修改时,所有的属性都会修改。而且它省略了为构造函数传递初始化参数的环节,所有的对象在默认情况下都将取得相同的值。
组合使用原型和构造函数模式
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。这是目前使用最广泛的创建自定义类型的方法。
function Person(name){
this.name=name;
this.friends=["james","chandler"];
}
Person.prototype={
construtor:Person,
sayName:function(){
alter(this.name);
}
}
var person1=new Person("jack");
var person2=new Person("rose");
person1.friends.push("yudi");
alert(person1.friends); //james,chandler,yudi
alert(person2.friends);//james,chandler
alert(person1.sayName == person2.sayName); //true
alert(person1.friends== person2.friends); //false
动态原型模式
动态原型模式将所有的信息都封装在构造函数中,并加了一个判断。
function Person(name){
this.name=name;
if(typeof this.sayName != "function"){
Person.prototype.sayName=function(){
alert(this.name);
}
}
}
if语句中的代码只会在初次调用构造函数时才会执行,当第二次访问时,因为原型中有sayName方法,所以只会初始化一次。