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操作符對這種對象也沒有意義。