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

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

不少job 的描述都說要求精通 javascript 面向對象編程,可是根據通常的套路,寫精通其實就是熟練,寫熟練其實就是通常,寫通常其實就是懵逼!javascript

3f9a9dd8a3501c03691b62129630155e.png

雖然話說如此,可是咱們仍是要熟練使用 javascript 面向對象編程的,畢竟這是js社會高能人才的其中一個標準,這裏我就用一個鮮活的例子來講明和理解咱們應該如何使用javascript 面向對象的方式來編程。java

1、野蠻方式構建對象

剛開始最初,咱們建立對象的方式是這樣的:編程

// 。。。。每次都要寫上面的一大段代碼,只是爲了建立一個 food
var food = new Object();
food.name = "蘋果";

food.sayName = function() {
  console.log("我是" + this.name);
};

可是這樣建立起來很麻煩,寫的代碼也是很長,若是要建立好多對象,例如我製造了10000個食物,就要寫10000次這一大段代碼了,因此後來聰明的工程師改成了這樣寫:函數

// 起碼比以前的少了幾行,也整潔了一些
var food = {
  name: "蘋果",
  sayName: function() {
    console.log("我是" + this.name);
  }
};

起碼代碼少了一些,可是仍是沒辦法很好解決我要寫100000段代碼的問題,因此再後來的人們就開始使用一些高級玩意來解決這個問題。性能

2、使用工廠模式構建對象

經過抽象出建立具體對象的過程,用函數來進行封裝,換句話來講,就是抽象了一個 food 的工廠,而後經過對這個工廠傳入不一樣的材料,來生成不一樣的食物。學習

function createFood(name) {
  var o = new Object();
  o.name = name;
  o.sayName = function() {
    console.log("我是" + this.name);
  };
  return o;
}

var food1 = createFood("蘋果");
var food2 = createFood("蘋果");

這裏能夠看到food1,food2 就是這樣被製造出來的,而後只須要少許的代碼(預先定義好一個生產工廠函數),就能夠完成大量的事情,完全解決了問題,實現了多快好爽的新局面。可是用了一段時間以後,隨之而來發現一個新問題,當食物多起來的時候,老闆貌似不知道哪些食物是屬於那些分類的(假設老闆是 zz),那怎麼辦呢?網站

// 都統一返回是[Function: Object],沒辦法用區分識別(賣個關子,你不用管那個constructor)
console.log(food1.constructor) // 返回[Function: Object]
console.log(food2.constructor) // 返回[Function: Object]

3、使用構造函數模式來區分本身人

通過一番智慧交流以後,聰明的人們想出了一個方法,使用一個在對象裏面的 constructor 函數來識別那些不同的對象,相似使用部門工牌來標記這我的是是屬於哪一個部門的。this

function Food(name) {
  this.name = name;
  this.sayName = function() {
    console.log("我是" + this.name);
  };
}

var food1 = new Food("蘋果");
var food2 = new Food("蘋果");

// 假設這裏有一個其餘的食物,多是冒充的
var food3 = new otherFood("蘋果");

由於要實現相似工牌的方式來識別,因此在建立food的工廠裏作一些調整:spa

  • 沒有顯式的建立對象,例如:var o = new Object();
  • 直接將屬性和方法付給了 this 對象
  • 沒有 return 語句
  • 函數使用了大寫字母開頭(這裏只是爲了區分這個函數的特別,按照慣例,大寫字母開頭的,通常都是 class 或者構造函數)
  • 使用了 new 來建立Food`對象

作了以上的改變以後,整個建立對象的模式被改變了:設計

  1. 首先定義了一個 Food 的構造函數(其實就是以前的工廠函數createFood,可是如今升級了)
  2. 經過 new 來建立一個對象(如今的 Food 用 new 來先建立)
  3. 將構造函數的做用域賦值給新對象,將this指向這個新對象(將升級版的工廠送給這個用 new 建立的 food)
  4. 執行構造函數的中的代碼(升級版的工廠會自動將裏面的零件和機器放到新的 Food 上,至關於組裝放在了食物自己 身上)
  5. 不須要主動 return,自動返回新對象(升級版的工廠會自動返回構造好的 food 對象)

經過這種方式,咱們製造出來的食物都會有一個 constructor 爲 Food 的標記來標識,若是看到不是的話,那確定就不是咱們製造的。

console.log(food1.constructor) // 返回[Function: Food]
console.log(food2.constructor) // 返回[Function: Food]
console.log(food3.constructor) // 返回[Function: OtherFood]

// 檢驗的方式有兩種
console.log(food1.constructor == Food) // 返回 true
console.log(food2.constructor == Food) // 返回 true
console.log(food3.constructor == Food) // 返回 false ,這個不是咱們製造的食物

console.log(food1 instanceof Food) // 返回 true
console.log(food3 instanceof Food) // 返回 false,這個不是咱們製造的食物

能夠看到,使用了新技術(constructor模式技術)以後,在沒有增長工做量的狀況下,解決了使人頭痛的問題,簡直是完美,不過過了一段時間以後,發現好像仍是有些瑕疵,使用構造函數constructor模式的時候,函數裏面的每一個方法都會在每一個實例上從新建立一遍,那麼最明顯的地方是:

console.log(food1.sayName == food2.sayName); // 返回 false

由於使用new來建立實例,new的話還會把構造函數裏面的方法也一塊兒建立,由於方法也是函數,而函數的實例化也會被new觸發:

// 省略了其餘部分,只關注方法部分
this.sayName = function() {
    console.log("我是" + this.name);
};

this.sayName = new function() {
    console.log("我是" + this.name);
}();

這樣就會形成內存和時間和性能的浪費,明明不須要從新重建新的函數實例的。

其實在以前的工廠模式裏面,也存在這個問題,不過工廠模式更完全,直接徹底建立一個新對象,而構造函數模式的話只是方法會被從新建立。

那怎麼解決呢?會用到原型模式,下回分解。

參考內容

  1. 紅寶書,《javascript 高級程序設計第三版》

版權信息

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