工厂模式
创建函数来封装特定的接口和创建对象的细节。函数可以通过接受对象来创建一个包含属性和方法的对象,可以反复的调用函数。
优点:增加了代码的复用性 缺点:无法识别对象类型
function createPerson(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 person1 = createPerson('Nicholas',29,'Software Engineer');
var person2 = createPerson('Greg',27,'Doctor');
构造函数模式
可以通过创建自定义的构造函数,来定义自定义对象类型的属性和方法。
与工厂模式的不同:没有显式地创建对象,直接将属性和方法赋给了this对象,没有return语句
优点:可以将它的实例标识为一种特定的类型
缺点:每个方法都要在实例上创建一遍,浪费内存空间
function Person(name,age,job){
this.name = name;
this.age = age;
this.jog = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person('Nicholas',29,'Software Engineer');
var person2 = new Person('Greg',27,'Doctor');
内存空间不同
console.log(person1.sayName === person2.sayName);//false
改进方法:把函数定义转移到构造函数外部
function Person(name,age,job){
this.name = name;
this.age = age;
this.jog = job;
this.sayName = sayName;
}
function sayName(){
alert(this.name);
};
var person1 = new Person('Nicholas',29,'Software Engineer');
var person2 = new Person('Greg',27,'Doctor');
console.log(person1.sayName === person2.sayName);//true
优点:解决了方法被重复创建的问题
缺点:在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。而且,如果对象需要定义很多方法,就要定义很多全局函数,会污染全局空间,这个自定义的引用类型没有封装性可言了。
原型模式
使用原型对象,可以让所有实例共享它的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中
function Person(){
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
}
}
var person1 = new Person();
person1.sayName();//"bai"
var person2 = new Person();
person2.sayName();//"bai"
alert(person1.sayName == person2.sayName);//true
缺点:引用类型值属性会被所有的实例对象共享并修改
更简单的原型语法
为了减少不必要的输入,也为了从视觉上更好地封装原型的功能,用一个包含所有属性和方法的对象字面量来重写整个原型对象
function Person(){
}
Person.prototype = {
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName : function(){
alert(this.name);
}
};
var person1 = new Person();
person1.sayName();//"Nicholas"
alert(person1.constructor === Person);//false
alert(person1.constructor === Object);//true
缺点:constructor无法在指向Person函数,可以在原型函数中设置constructor(constructor:Person)来解决这个问题
组合使用构造函数和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式和原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性,这种组合模式还支持向构造函数传递参数。实例对象都有一份实例属性的副本,同时又共享对方法的引用,最大限度地节省了内存。该模式是目前使用最广泛、认同度最高的一种创建自定义对象的方法
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["shelby","Court"];
}
Person.prototype = {
constructor: Person,
sayName : function(){
console.log(this.name);
}
}
var person1 = new Person("Nicoholas",29,"Software Engineer");
var person2 = new Person("hu",25,"Software Engineer");
person1.friends.push("Van");
alert(person1.friends);// "shelby","Court","Van";
alert(person2.friends);// "shelby","Court";
alert(person1.friends === person2.friends);//false
alert(person1.sayName === person2.sayName);//true
动态原型模式
动态原型模式将所有的信息都封装到了构造函数中,然后通过检查某个应该存在的方法是否有效,来决定是否初始化原型对象
优点:将原型对象合并到构造函数中,使得代码更加整齐,也减少了全局空间的污染
如果原型对象中包含多个语句,只需要检测其中一个语句即可
不要用字符字面量 重写原型,会切断现有实例和新原型之间的联系
function Person(name,age,job){
//属性
this.name = name;
this.age = age;
this.job = job;
//方法
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
console.log(this.name);
};
}
}
var friend = new Person("Nicholas",29,"Software Engineer");
friend.sayName();//'Nicholas'