讓 JavaScript 區別於其它語言的是什麼?原型繼承!

做者: Dmitri Pavlutin
譯者:前端小智
來源:sitepoint
點贊再看,養成習慣

本文 GitHub https://github.com/qq44924588... 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。javascript

最近開源了一個 Vue 組件,還不夠完善,歡迎你們來一塊兒完善它,也但願你們能給個 star 支持一下,謝謝各位了。前端

github 地址:https://github.com/qq449245884/vue-okr-treevue

只有瞭解了原型繼承,你才能說你懂 JS,原型影響着對象的工做方式。原型繼承常常會在面試中被問到,由於這個面試官能夠看出你對 JS 的瞭解程度。java

本文,主要是幫助你們可以更好的理解 JS 中的原型。git

1.簡介

JavaScript 僅具備基本類型,nullundefinedobject。 JS 和Java或PHP等語言相反,沒有類的概念能夠用做建立對象的模板。github

對象是可組合的結構,由多個屬性組成:鍵和值對。面試

例如,如下對象cat包含2個屬性:微信

const cat = { sound: 'Meow!', legs: 4 };

因爲我想在其餘對象中重用legs屬性,所以讓咱們將legs屬性提取到專門的對象pet工具

const pet = { legs: 4 };

const cat = { sound: 'Meow!' };

看起來還不錯!this

可是我仍然想讓cat擁有legs的屬性。 如何將 cat pet聯繫起來?

繼承能夠幫助咱們!

2. 原型對象

在 JS 中,一個對象能夠繼承另外一個對象的屬性。繼承屬性的對象被稱爲 prototype,也就是原型。

按照改定義,咱們可讓pet做爲 cat的原型,該原型將繼承legs屬性。使用對象字面量建立對象時,也能夠使用特殊屬性__proto__設置所建立對象的原型。

const pet = { legs: 4 };

const cat = { sound: 'Meow!', __proto__: pet };

cat.legs; // => 4

cat 對象如今從原型pet繼承了legs 。 如今,咱們能夠使用cat.legs,其值爲4

另外一方面,sound 屬性是一個自有屬性,由於它是直接在對象上定義的。

clipboard.png

JavaScript 原型繼承本質:對象能夠從其餘對象(原型)繼承屬性。

你可能想知道:爲何首先須要繼承?

繼承解決了數據和邏輯重複的問題。 經過繼承,對象能夠共享屬性和方法。

const pet = { legs: 4 };

const cat = { sound: 'Meow!', __proto__: pet };
const dog = { sound: 'Bark!', __proto__: pet };
const pig = { sound: 'Grunt!', __proto__: pet };

cat.legs; // => 4
dog.legs; // => 4
pig.legs; // => 4

catdogpig 都重複使用了屬性legs

注意__proto__已過期,但爲了簡單起見,我使用它。 在生產環境中,建議使用Object.create()

2.1 自有與繼承的屬性

若是對象本身的屬性和繼承屬性名稱同樣,JS 會優先選擇自有屬性。

在如下示例中,chicken對象具備本身的屬性legs,但還繼承了具備相同名稱legs的屬性:

const pet = { legs: 4 };

const chicken = { sound: 'Cluck!', legs: 2, __proto__: pet };

chicken.legs; // => 2

cat 對象從原型pet繼承了legs 。 如今,您能夠使用屬性訪問器cat.legs,其值爲4。

chicken.legs的值爲2。JavaScript在繼承上選擇自有屬性legs

clipboard.png

若是刪除自有屬性,則 JS 會選擇繼承的屬性!

const pet = { legs: 4 };

const chicken = { sound: 'Cluck!', legs: 2, __proto__: pet };

chicken.legs; // => 2
delete chicken.legs;
chicken.legs; // => 4

3.隱式原型

建立對象時,未明確設置原型,JS 會爲咱們建立的對象類型分配一個隱式原型。

咱們再來看看pet對象

const pet = { legs: 4 };

pet.toString(); // => `[object Object]`

pet只有一個屬性legs,可是,咱們能夠調用方法pet.toString()。 這個toString()哪裏來的?

建立pet 對象後,JS 爲其分配了一個隱式原型對象。 pet從這個隱式原型中繼承了toString()方法:

Object.getPrototypeOf() 方法返回指定對象的原型(內部[[Prototype]]屬性的值)。

4. 原型鏈

咱們再建立tail 對象,讓他也成爲pet的原型:

const tail = { hasTail: true };

const pet = { legs: 4, __proto__: tail };

const cat = { sound: 'Meow!', __proto__: pet };

cat.hasTail; // => true

cat從它的原型pet繼承了legs 的屬性。 可是cat也從其原型的原型tail 繼承了hasTail

clipboard.png

訪問屬性myObject.myProp時,JS 會在myObject自身的屬性內,對象的原型,原型的原型中依次搜索myProp,以此類推,直到遇到null做爲原型。

換句話說,JavaScript在原型鏈中尋找繼承的屬性。

5. 但 JavaScript有類

從剛開始講的 JS 只有對象,沒有類,你可能就已經感到困惑,你在說什麼鬼。這多是由於在 ES6 中 你已經開始使用class關鍵字了。

例如,你能夠編寫一個Pet類:

class Pet {
  legs = 4;

  constructor(sound) {
    this.sound = sound;
  }
}

const cat = new Pet('Moew!');

cat.legs;           // => 4
cat instanceof Pet; // => true

並在實例化該類時建立cat

其實 ,JS 中的class 語法是原型繼承之上的語法糖

上面的基於類的代碼片斷等效於如下內容:

const pet = {
  legs: 4
};

function CreatePet(sound) {
  return { sound, __proto__: pet };
}
CreatePet.prototype = pet;

const cat = CreatePet('Moew!');

cat.legs;                 // => 4
cat instanceof CreatePet; // => true

CreatePet.prototype = pet賦值是使cat instanceof CreatePet值爲true所必需的。

6.總結

在JavaScript中,對象從其餘對象(原型)繼承屬性,這就是原型繼承的一個概念。

JS 在對象的原型中尋找繼承的屬性,也在原型的原型中尋找繼承的屬性,等等。

雖然最初的原型繼承看起來很笨拙,可是理解它以後,咱們會喜歡它的簡單性和可能性。


代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:https://dmitripavlutin.com/ja...

交流

文章每週持續更新,能夠微信搜索「 大遷世界 」第一時間閱讀和催更(比博客早一到兩篇喲),本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,整理了不少個人文檔,歡迎Star和完善,你們面試能夠參照考點複習,另外關注公衆號,後臺回覆福利,便可看到福利,你懂的。

相關文章
相關標籤/搜索