一、工厂模式
function createPerson(name,age,job){
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=fucntion(){
alert(this.name);
};
return o;
}
var person1=createPerson("Nicholas",29,"Software Engineer");
var person2=createPerson("Greg",27,"Doctor");
优点:
抽象了创建具体对象的过程,解决了创建多个相似对象的问题
缺点:
没有解决对象识别的问题(即怎样知道一个对象的类型)
二、构造函数模式
function Person(name ,age,job){
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);
};
}
var person1=new Person("Nicholas",29,"Software Engineer");
var person2=new Person("Greg",27,"Doctor");
构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。任何函数,只要通过new操作符来调用,那它就可以作为构造函数,而任何函数,如果不通过new操作符来调用,那它跟普通函数也不会有什么两样。
构造函数模式的优点:
解决了对象识别的问题:Person1和Person2分别保存着Person的一个不同的实例。这两个对象又有一个constructor(构造函数)属性,该属性指向Person,如下所示:
alert(person1.constructor==Person); //true
alert(person2.constructor==Person); //true
构造函数模式的缺点:
每个方法都要在每个实例上重新创建一遍。以这种方式创建函数,会导致不同的作用域链和标识符解析,但创建Function新实例的机制仍然是相同的,然而创建两个完成同样任务的Function实例是没有必要的。
三、原型模式
function Person(){
}
Person.prototype={
constructor:Person,
name:"Nicholas",
age:29;
job:"Software Engineer",
friends:["Shelby","Court"],
sayName:function(){
alert(this.name);
}
};
var person1=new Person();
var person2=new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends==person2.friends); //true
原型模式优点:
可以让所有对象实例共享它所包含的属性和方法,也就是不用在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
原型模式缺点:
1.它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值
2.原型模式最大的问题也是其共享的本性导致的。特别是对于包含引用属性类型值的属性,问题比较突出,比如上面代码中的person1.friends==person2.friends.
四、组合使用构造函数模式和原型模式
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friends=["Shelby","Court"];
}
Person.prototype={
constructor:Person,
sayName:function(){
alert(this.name);
}
};
var person1=new Person("Nicholas",29,"Software Engineer");
var person2=new Person("Greg",27,"Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends===person2.frineds); //false
alert(person1.sayName===person2.sayName); //true
组合模式优点:
1.每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存
2.这种混成模式还支持向构造函数传递参数
这种构造函数与原型混成的模式,是目前在ECMAScript 中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。
五、动态原型模式
function Person(name ,age, job){
//属性
this.name=name;
this.age=age;
this.job=job;
//方法
if(typeof this.sayName!="function"){
Person.prototype.sayName=function(){
alert(this.name);
}
}
}
var friend=new Person("Nicholas",29,"Software Engineer");
friend.sayName();
动态原型模式优点:
它把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。
if语句检查的可以是初始化之后应该存在的任何属性或方法——不必用一大堆if语句检查每个属性和每个方法,只要检查其中一个即可。
注意:
在使用动态原型模式时,不能使用对象字面量重写原型。如果在已经创建了实例的情况下重写原型,那么就会切断现有实例与新原型之间的联系。
六、寄生构造函数模式
function Person(name , age , job){
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){
alert(this.name);
};
return o;
}
var friends=new Person("Nicholas",29,"Software Engineer");
friends.sayName(); //"Nicholas"
除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实是一模一样的。构造函数在不返回值的情况下,默认会返回新对象实例。而通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值。
注意:
关于寄生构造函数模式,返回的对象与构造函数或者与构造函数的原型属性之间没有关系,也就是说,构造函数返回的对象与在构造函数外部创建的对象没什么不同。不能依赖instanceof操作符来确定对象类型。建议在可以使用其他模式的情况下,不要使用这种模式。
七、稳妥构造函数模式
function Person(name,age,job){
//创建要返回的对象
var o=new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName=function(){
alert(name);
};
//返回对象
return o;
}
var friends=Person("Nicholas",29,"Software Engineer");
friends.sayName(); //"Nicholas"
稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:
1.实例方法不引用this
2.不使用new操作符调用构造函数
注意:
变量friends中保存的是一个稳妥对象,而除了调用sayName()方法外,没有别的方式可以访问其数据成员。
稳妥构造函数模式提供的这种安全性,使得它非常适合在某些安全执行环境——例如,ADsafe(www.adsafe.org)和Caja(http://code.google.com/p/google-caja/)提供的环境下使用。