一、工廠模式
function createCar(color,type){
var car = new Object();
car.color = color;
car.type = type;
car.sayColor = function(){
alert(this.color);
};
return car;
}
var car1 = createCar('red','CDV');
var car2 = createCar('blue','SUV');
car1.sayColor(); //red
car2.sayColor(); //blue
console.log(car1);
console.log(car2);
運行結果:
-
特點:用函數來封裝創建對象的細節,內部最終返回一個對象。
-
優點:解決了創建多個相似對象的問題
-
缺點:不能確定對象的類型(即無法用 instanceof 去判斷)
二、構造函數模式
function Car(color,type){
this.color = color;
this.type = type;
this.sayColor = function(){ alert(this.color); }; }
var car1 = new Car('red','CDV');
var car2 = new Car('blue','SUV');
car1.sayColor(); //red
car2.sayColor(); //blue
console.log(car1);
console.log(car2);
console.log(car1 instanceof Car);
1、特點:
-
- 沒有顯式創建對象
- 屬性和方法賦給了this
- 沒有 return 語句
2、調用過程:
-
- 使用new操作符創建一個新對象
- 將構造函數的作用域賦給新對象(this就指向了新對象)
- 執行構造函數里的代碼
- 返回新對象
3、優點:可將實例標識為一種特定類型(比如car1的類型就是Car,可用instanceof判斷)
4、缺點:每個方法都要在每個實例上重新創建一遍。可以將其寫在外部共享,但又失去了封裝性。如下:
function Car(color,type){
this.color = color;
this.type = type;
}
function sayColor(){ alert(this.color); }
var car1 = new Car('red','CDV');
var car2 = new Car('blue','SUV');
sayColor.call(car1); //red,這里通過call來改變作用域 sayColor.call(car2); //blue,這里通過call來改變作用域 console.log(car1);
console.log(car2);
console.log(car1 instanceof Car);
三、原型模式
function Car(){
}
Car.prototype.color = 'red';
Car.prototype.type = 'SUV';
Car.prototype.sayColor = function(){
alert(this.color);
}
var car1 = new Car();
var car2 = new Car();
car1.sayColor(); //red 來自原型
car2.sayColor(); //red 來自原型
car1.color = 'blue'; //屏蔽了原型的color,但沒有覆蓋,原型的color還在
alert(car1.color); //blue 來自實例
alert(car2.color); //red 來自原型
1、原型、構造函數與實例的關系:每個構造函數都有一個原型對象(prototype屬性),原型對象包含一個指向構造函數的指針(constructor),實例包含一個指向原型對象的指針(__proto__)。實例與構造函數沒有直接關系。
2、訪問一個對象屬性的過程:在上面代碼中,比如car2.color ,先問car2實例上有color屬性嗎?沒有,則查找原型,car2原型上有color屬性嗎?有,則返回。再比如car1.color ,先問car1上有color屬性嗎?有,則返回。就不需要查找原型了。
3、判斷屬性是否存在於實例中:hasOwnProperty() , true——實例
4、優點:屬性和方法可以共享,並且可以在實例上重新定義屬性,而不改變原型。
5、缺點:由於共享,對於引用類型,在實例上進行修改,也會改變原型的值。如下:
function Person(){
}
Person.prototype = {
constructor:Person, //防止一些操作切斷構造函數與原型的關系
name:'Jemma',
friends:['Lucy','Jack']
}
var person1 = new Person();
var person2 = new Person();
console.log(person1.name); //Jemma
console.log(person2.name); //Jemma
//改變基本類型的屬性
person1.name = 'King';
console.log(person1.name); //King
console.log(person2.name); //Jemma
//改變引用類型
person1.friends.push('Marry');
console.log(person1.friends); //["Lucy", "Jack", "Marry"]
console.log(person2.friends); //["Lucy", "Jack", "Marry"]
四、構造函數+原型模式(一般使用這個)
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype = {
constructor:Person, //防止一些操作切斷構造函數與原型的關系
sayName:function(){
alert(this.name);
}
}
var person1 = new Person('Jemma',19);
var person2 = new Person('King',21);
console.log(person1.name); //Jemma
console.log(person2.name); //King
person1.sayName(); //Jemma
person2.sayName(); //King
特點:所有實例共享的屬性和方法原型中定義;自己獨有的在構造函數定義。
優點:既可以共享,又有特定類型。
其實關於這些細節可以講很多東西,我這里只是簡單總結一下。