這篇文章的重點講的是關於JavaScript中對象的繼承,這是面向對象編程很重要的一個方面。A 對象繼承自B 對象,就能直接擁有 B 對象的全部屬性和方法,做用是避免了代碼的複用,節省代碼量。javascript
而大部分面向對象的編程語言,都是經過「類」(class)來實現對象的繼承。傳統上,JavaScript 語言的繼承不經過 class(ES6 引入了 class 語法,基於 class 的繼承不在這裏介紹),而是經過「原型對象」(prototype
)實現,所以,這裏把「繼承」着重拿出來說,就爲了體現這個不一樣。java
JavaScript的繼承得靠原型/原型鏈來實現,固然原型/原型鏈不是這篇文章的重點,以前的文章也已經介紹過了,因此這裏咱們來複習一下便可。git
其實原型的概念很簡單,我以爲用如下簡短的幾句話就能歸納徹底了:github
__proto__
指向一個對象,也就是原型constructor
找到構造函數,構造函數也能夠經過 prototype
找到原型__proto__
找到 Function
對象__proto__
找到 Object
對象__proto__
鏈接起來,這樣稱之爲原型鏈。當前對象上不存在的屬性能夠經過原型鏈一層層往上查找,直到頂層 Object
對象,頂層 Object
對象最終指向null
我以爲原型中最重要的內容其實就這些了,不必看太多關於原型的文章,到頭來只是會愈來愈糊塗,若是硬要推薦原型參閱資料的話,《JavaScript高級程序設計》這本書,當之無愧!編程
經過上面的介紹,咱們知道JavaScript中的繼承是經過原型/原型鏈來體現的,先看幾行代碼:app
function Foo() { }
var f1 = new Foo();
f1.a = 10;
Foo.prototype.a = 100;
Foo.prototype.b = 200;
console.log(f1.a); // 10
console.log(f1.b); // 200
console.log(f1.c); // undefined
複製代碼
以上代碼中,f1
是Foo
函數經過new
構造出來的對象,f1.a
是f1
對象的基本屬性,而f1.b
是從Foo.prototype
繼承獲得的,由於f1.__proto__
指向的是Foo.prototype
。編程語言
這裏有一個重要的規則:當訪問一個對象的屬性時,首先在基本屬性中查找,若是沒有,再沿着__proto__
這條鏈往上找,看是否在鏈上,有的話就能繼承這一屬性,若是沒有,就返回undefined
,這就是原型鏈,又複習一遍咯。函數
看圖直觀一些,這裏仍是採用反覆用的原型/原型鏈經典圖:ui
上圖中,訪問f1.a
時,f1
的基本屬性中有a
,則不會繼續沿着__proto__
找,直接讀出基本屬性a
的值;而訪問f1.b
時,f1
的基本屬性中沒有b
,因而沿着__proto__
找到了Foo.prototype.b
。spa
那咱們如何在實際應用中區分一個屬性究竟是基本屬性仍是在原型鏈中的公有屬性呢?這裏能夠好好利用一下這個屬性——hasOwnProperty
,一下就能測出誰是基本屬性,當在for…in…
循環中,須要額外注意。
hasOwnProperty()
方法會返回一個布爾值,指示對象自身屬性中是否具備指定的屬性,因此上圖中,右邊的只打印出a
一個值,由於b
是在Foo.prototype
上的,不屬於自身屬性。
那f1
的這個hasOwnProperty()
方法,f1
自身沒有,Foo.prototype
中也沒有,又是從何而來呢?
仍是引用那張原型/原型鏈經典圖,從圖上來看,hasOwnProperty()
方法是從Object.prototype
中繼承來的:
因此對象的原型鏈是沿着__proto__
這條線走的,所以在查找f1.hasOwnProperty
屬性時,由於自身沒有這一屬性,就會沿着原型鏈一直查找到Object.prototype
上有這一屬性,若是沒找到則返回undefined
。
因爲全部的對象的原型鏈都會最終找到Object.prototype
,所以全部的對象都會有Object.prototype
中的方法,好比toString
、valueOf
等這些公有屬性,這就是所謂的「繼承」。
固然這只是一個例子,你能夠自定義函數和對象來實現本身的繼承,這一點後續文章會有專門介紹。
這裏再說一個函數的例子來加深理解吧。
咱們都知道每一個函數都有apply
,call
方法,都有length
,arguments
,caller
等屬性。爲何每一個函數都有?這確定是「繼承」來的。在介紹instanceof
這篇文章中也提到,函數是由Function
函數建立,都繼承自Function.prototype
中的方法。不信能夠在Chrome中打印出:
直接能夠看到了吧,有call
、length
等這些屬性。
那怎麼還有hasOwnProperty
呢?上圖中hasOwnProperty
右邊顯示Object
,表明Function.prototype
繼承自Object.prototype
。有疑問能夠再看看這張原型/原型鏈經典大圖,Function.prototype.__proto__
會指向Object.prototype
。
最後仍是那句話,當你徹底搞懂上面這張圖的時候,就是你掌握原型、原型鏈的時候了。
若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!