1. 工厂模式(不完美)
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
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('haojie', 28, "Web Developer");
person1.sayName(); // Nicholas
person2.sayName(); // haojie
2. 构造函数模式(不完美)
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
}
}
var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('haojie', 28, 'Web Developer');
person1.sayName();
person2.sayName();
其中第5行sayName Function实际等同于
this.sayName = new Function("alert(this.name)"); // 与声明函数在逻辑上是等价的
每个Person实例都包含一个不同的Function实例,下面的代码能证明这两个函数是不相等的
console.log(person1.sayName == person2.sayName); //false
然而,创建两个完全同样的任务的Function实例的确没有必要。
3. 原型模式(不完美)
function Person(){
}
Person.prototype = {
constructor: Person,
name: 'Nicholas',
age: 29,
job: 'Software Engineer',
friends: ['Shelby', 'Court'],
sayName: function(){
console.log("sayName function say: " + this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
console.log(person1.friends); // "Shelby, Court, Van"
console.log(person2.friends); // "Shelby, Court, Van"
console.log(person1.friends == person2.friends);// true
在此,Person.prototype对象有一个名为friends的属性, 该属性包含一个字符串数组。然后创建了Person的两个实例。接着,修改了person1.friends引用的数组,想数组中添加了一个字符串。由于friends数组存在于Person.prototype而非person1中,所以刚刚提到的修改也会通过person2.friends(与person1.friends指向同一个数组)反映出来。
4. 组合使用构造函数模式和原型模式(Nicholas 推荐)
// 实例属性定义在【构造函数】中
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", 29, "Doctor");
person1.friends.push("Van");
console.log(person1.friends); // Shelby, Court, Van
console.log(person2.friends); // Shelby, Court
console.log(person1.friends == person2.friends); // false
console.log(person1.sayName == person2.sayName); // true
5. 动态原型模式(Nicholas推荐)
function Person(name, age, job, friends){
// 属性
this.name = name;
this.age = age;
this.job = job;
this.friends = friends;
// 方法
// 这里只有在sayName不存在的情况下,才会将它添加到原型中
// 也就是new person1的时候会被call到,new person2的时候就不会走这里了
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
console.log(this.name);
};
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer", ["Shelby", "Court"]);
var person2 = new Person("haojie", 29, "Software Engineer", ["Shelby", "Court"]);
person1.sayName(); // Nicholas
person2.sayName(); // haojie
person1.friends.push('Van');
console.log(person1.friends); // Shelby,Court,Van
console.log(person2.friends); // Shelby,Court
console.log(person1.friends == person2.friends); // false
console.log(person1.sayName == person2.sayName); // true
6. 寄生(parasitic)构造函数模式(不推荐)
不能使用person1 instanceof Person 操作符来确定对象类型
7. 稳妥(durable objects)构造函数模式(安全)
function Person(name, age, job, friends){
// 创建要返回的对象
var o = new Object();
// 可以在这里定义私有变量和函数
// 添加方法
o.sayName = function(){
console.log(name);
};
// 返回对象
return o;
}
var person = Person('Nicholas', 29, 'Software Engineer');
person.sayName(); // Nicholas
console.log(person instanceof Person); // false
这样,变量person中保存的是一个稳妥对象,而除了调用sayName()方法外,没有别的方式可以访问其数据成员。稳妥构造函数提供的这种安全性,使得它非常适合在某些安全执行环境下使用。
与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间也没有关系(因为用的是new Object, 然后return的方法),因此instanceof操作符对这种对象也没有意义。