我來從新學習 javascript 的面向對象(part 3)

續上一集內容,有一些數據不須要共享的時候,可是又想實現共享數據處理,魚與熊掌,都要兼得(老闆就是這麼霸氣),那麼通過工程師們的智慧交流,他們發現現實並不是那麼殘酷,還有一些辦法可取的,也就是組合使用構造函數模式和原型模式動態原型模式javascript

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

組合使用構造函數模式和原型模式的特色主要體如今:java

  • 構造函數模式用於定義實例屬性
  • 原型模式用於定義方法和共享屬性

效果就是,每一個實例對象都會有本身的一份實例屬性,但又同時又共享着對方法的引用,既節省了資源也知足了業務要求。數組

// 構造函數用於定義實例屬性
function Food(name) {
  this.name = name;
  this.place = ["巴西", "印度"];
}
// 原型模式用於定義方法和共享屬性
Food.prototype = {
  constructor: Food,
  sayName: function() {
    console.log("我是" + this.name);
  }
};

var food1 = new Food("蘋果");
var food2 = new Food("蘋果");
console.log(food1.place == food2.place); // 返回 false
food2.place.push("俄羅斯");
console.log(food1.place); // 返回 [ '巴西', '印度' ]
console.log(food2.place); // 返回 [ '巴西', '印度', '俄羅斯' ]

能夠看到 palce 數組並非同一個,而且經過對 food2的 place 數組賦值以後也不會影響 food1的 palce 數組的值,證實他們是互相獨立的。安全

之因此有這麼屌炸天的效果,就是由於利用了構造函數和原型模式各自的特色,互相補充。

2、動態原型模式

動態原型模式的特色是,在構造函數裏面增長判斷處理是否添加原型對象屬性。函數

function Food(name, place) {
  this.name = name;
  this.place = place;
  if (typeof this.sayName !== "function") {
    Food.prototype.sayName = function() {
      console.log("我是" + this.name);
    };
  }
}

var food1 = new Food("蘋果", ["巴西", "印度"]);
food1.sayName(); // 返回 我是蘋果
  • 經過在構造函數執行的時候來判斷是否將共享的東西添加到原型對象裏面,這樣就不怕以前出現的先 new 實例化對象,而後再添加原型對象的屬性的問題了(回想一下原型對象被重寫以後,原型對象丟失,實例沒法使用原來的原型對象的數據的問題)。
  • 更符合 OOP 開發習慣,不須要將構造函數和原型對象分開單獨處理,能夠寫在一塊兒。
動態原型模式和組合使用構造函數模式和原型模式的原理其實很相似,都是各自利用了構造函數和原型模式的獨特的特色來實現的,不過在實現的過程當中用了一些取巧,因此致使了他們的分別,細細回想一下就明白了。

3、寄生構造函數模式

這個只是瞭解一下便可,由於實際中用得很少,可是須要擴大知識面,不管從裝逼仍是裝逼都仍是須要的。

寄生這個詞其實不太好理解,英文原文是叫 parasitic 直接翻譯過來就是寄生了。若是硬要理解,就是建立的實例對象實際上是依附上去的,跟構造函數和原型對象自己並無任何關係,就好像寄生蟲和動物,他們僅僅只是寄生在上面而已。網站

function Food(name) {
  var o = new Object(); 
  o.name = name;
  o.sayName = function() {
    console.log("我是" + this.name);
  };
  return o; // 重寫返回值
}

var food1 = new Food("蘋果");
console.log(food1.name); // 返回 蘋果
food1.sayName(); // 返回 我是蘋果
  • 這裏跟工廠模式極其類似,但這裏使用了 new 進行實例化,換言之,也就是執行了構造函數來進行實例化。
  • 構造函數在不返回值的狀況下,默認會返回新對象實例,而經過構造函數的末尾添加一個 return 語句,能夠重寫這個返回值。
  • 由於每次都是new Object(); ,並且構造函數的返回值被重寫了,也就是說這個返回的新對象跟構造函數,跟原型對象是沒有關係的,他們同時具備工廠函數和構造函數的缺點。
  • 這裏可以訪問 name,由於這裏的 name 屬性是暴露到返回的對象上面了,成爲返回的對象的屬性,就跟 sayName 方法同樣,能夠被外部訪問了。
他有一個嚴重的問題,就是原型對象和實例和構造函數之間沒辦法關聯,這樣不適合在有必定規模複雜度的程序開發中使用。(由於他每次都會new Object(),重置原型對象的信息)

4、穩妥構造函數模式

這個只是瞭解一下便可,由於實際中我還沒用過,可是須要擴大知識面,不管從裝逼仍是裝逼都仍是須要的。

所謂穩妥對象,是指沒有公共屬性,並且其方法也不引用 this 對象,並且也不能被篡改,穩得一逼。this

function Food(name) {
  var o = new Object();
  var color = 'red';
  o.sayName = function() {
    console.log("我是" + name);
    console.log("顏色是" + color);
  };
  return o;
}

var food1 = Food("蘋果");
console.log(food1.name); // 返回 undefined
console.log(food1.color); // 返回 undefined
food1.sayName(); // 返回 我是蘋果,顏色是red
  • 能夠看到這裏不使用this,也不使用 new 來實例化對象。
  • 不能經過其餘方式訪問 name 屬性,由於沒有name 屬性沒有被暴露出來。
  • 只能經過暴露出來的方法來訪問對象內部的屬性,間接保護了內部私有屬性。
穩妥模式適合在一些安全環境(禁止使用 this,而且也須要保護私有屬性)裏面使用。
他依然有一個嚴重的問題,就是原型對象和實例和構造函數之間沒辦法關聯,這樣不適合在有必定規模複雜度的程序開發中使用。(由於他每次都會new Object(),重置原型對象的信息)

5、文末咱們又遇到新問題了

公司業務愈來愈大了,公司的產品須要作一些分類,例如動物要分肉食動物,菜食動物,食物要分水果和蔬菜和肉類等,水果下面還要分蘋果,香蕉等等,要是按照如今的模式,看來是要有多少種就要寫多少種,而後還可能會致使一些種類屬性重複,老司機一眼就看出來,須要作一些種類繼承了,可是要怎麼作呢?spa

參考內容

  1. 紅寶書,javascript 高級程序設計第三版
  2. 淺談穩妥構造函數模式的實現原理與機制

版權信息

做者: 慫如鼠
網站: https://www.whynotbetter.com 本做品著做權歸做者全部,商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索