JavaScript建立對象的幾種重要模式

1、工廠模式

1. 代碼示例

function person(name, age) {
  var p = new object();
  p.name = name;
  p.age = age;
  p.sayName = function() {
    console.log(this.name);
  };
  return p;
}

var person1 = person('Bonnie', 26);
var person2 = person('Summer', 24);

2. 優勢

解決了建立多個類似對象的問題。html

3. 缺點

沒有解決對象識別的問題。數組

2、 構造函數模式

1. 代碼示例

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayName = function() {
    console.log(this.name);
  }
}

var person1 = new Person('Bonnie', 26);
var person2 = new Person('Summer', 24);

牢記:構造函數在不返回值的狀況下,默認會返回新對象的實例(構造函數模式)。 若是在構造函數內部末尾添加一個return語句,能夠重寫調用構造函數時返回的值(寄生構造函數模式)。安全

2.優勢

建立自定義的構造函數意味着能夠將它的示例標誌爲一種特定的類型(執行person1 instanceof Person爲true)。這就是它比工廠模式更勝一籌的地方。app

3.缺點

每一個方法都要在每一個實例上建立一遍。也就是說,使用構造函數模式建立的每一個實例都包含着各自獨有的同名函數。然而,建立兩個完成一樣任務的同名函數並無必要。函數

能夠像這樣使構造函數建立的每一個實例都引用一個方法:ui

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayName = sayName;
}
function sayName() {
  console.log(this.name);
}

可是這樣帶來的問題是被構造函數的不一樣實例共同引用的這個方法存在於全局做用域中,這一方面破壞了全局做用域,另外一方面也破壞了該自定義類型的封裝性。this

3、 原型模式

1. 代碼示例

function Person() {
}

Person.prototype.name = "Bonnie";
Person.prototype.age = 26;
Person.prototype.sayName = function() {
  console.log(this.name)
}

var person1 = new Person();
var person2 = new Person();

2. 優勢

可讓全部對象實例共享它所包含的屬性和方法。prototype

3. 缺點

首先,它省略了爲構造函數傳遞初始化參數這一環節,這樣全部實例默認都會取得相同的屬性值。設計

更嚴重的是,其共享的本質對於引用類型的屬性值(如數組)是很是不適合的:對於修改一個實例上引用類型的屬性值也會修改另外一個實例上的這個屬性值。不過,其共享本質對於函數很是合適,由於方法原本就是共用的。而其對於基本值的屬性也比較合適,由於能夠經過在實例上添加同名的屬性名來覆蓋原型中的屬性。code

詳見個人另外一篇博客《原型與原型鏈》 的"1、建立對象的重要模式:原型模式"。

4、 組合使用構造函數模式和原型模式

1.代碼示例

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.friends = ['Spring', 'Huiyun'];
}
Person.prototype.sayName = function() {
  console.log(this.name);
}

var person1 = person('Bonnie', 26);
var person2 = person('Summer', 24);

2. 優勢

實例屬性都在構造函數中實現,共享的屬性和方法在原型中定義,是使用最廣、認同度最高的一種建立自定義類型的方式。也是默認方式。

5、動態原型模式

1. 代碼示例

function Person(name, age) {
  this.name = name;
  this.age = age;

  if (typeof this.sayName != 'function') {
    Person.prototype.sayName = function() {
      console.log(this.name);
    }
  }
}

2. 優勢

只有在某方法不存在的狀況下,纔將該方法添加到原型上。添加到原型上這段代碼只會在初次調用構造函數時纔會執行。對原型所作的修改會馬上反映到全部實例中。

注意:不能使用對象字面量重寫原型,由於若是已經建立了實例,那麼重寫原型會切斷現有實例和新原型之間的聯繫。

6、寄生構造函數模式

1. 代碼示例

function Person(name, age) {
  var o = new Object();
  o.name = name;
  o.age = age;
  o.sayName = function() {
    console.log(this.sayName);
  }
  return o;
}
var person1 = new Person('Bonnie', 26);

除了使用new操做符並把包裝的函數叫作構造函數以外,該模式跟工廠模式是如出一轍的。構造函數在不返回值的狀況下默認返回新對象實例。而經過在構造函數內部末尾添加return語句,能夠重寫調用構造函數時返回的值。

2. 優勢

該模式適於爲特殊對象(如Array)建立具備新屬性、新方法的實例。也就是說適於在某些已有的特殊類型(如Array)的基礎上建立新的特殊類型(如SpecialArray)。

例如能夠在Array的基礎上,建立具備額外方法的數組:

function SpecialArray() {
  var o = new Array();
  o.push.apply(o, arguments);
  o.getPipedStr = function() {
    return this.join('|');
  }
  return o;
}

var colors = new SpecialArray('red', 'blue', 'green');
console.log(colors);// ["red", "blue", "green", getPipedStr: ƒ]
console.log(colors.getPipedStr);//"red|blue|green"

3. 缺點

該模式返回的對象與構造函數以及構造函數的原型之間毫無關係。也就是說,該模式返回的對象與在構造函數外部超級多對象沒什麼不一樣。因此構造函數所表示的類型並非實例的類型。

以上例來講:

colors instanceof SpecialArray;// false

7、 穩妥構造函數模式

1. 代碼示例

function Person(name, age) {
  var o = new Object();
  //私有變量
  var job = 'developer';

  o.sayName = function() {
    console.log(name);
  }
  o.sayJob = function() {
    console.log(job);
  }
  return o;
}
var person1 = new Person('Bonnie', 26);
person.sayName()//'Bonnie'
person.sayJob()//'Job'

該方式建立的對象,除了sayName、sayJob方法之外,沒有別的辦法訪問變量name、job。

2. 優勢

該模式提供了固定的方法來訪問構造函數中的原始數據(構造函數參數、私有變量)。除提供的方法外,沒有其餘辦法能夠訪問其構造函數中的原始數據。這種安全性使得穩妥構造函數模式很是適合在某些安全執行環境(如ADsafe、Caja)下使用。

參考資料

《JavaScirpt高級程序設計》6.2

相關文章
相關標籤/搜索