Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain. --- MDN
當咱們在一個obj對象上查找是否具備某個屬性的時候,這個過程是這樣的:
1.如今obj 對象中查找是否有該屬性,若是有,查找終止。(也就是說若是obj對象上面和它的原型上又一個同名屬性,那麼對象上面的屬性優先。)
2.若是沒有,則查看當前obj是否具備__proto__。這個__proto__就是obj原型的引用。若是obj對象沒有原型,那麼查找終止。
3.若是obj有原型,就查找obj的原型上是否有這個屬性。若是有,查找終止。返回這個屬性。
4.若是obj的原型上沒有這個屬性,則查看obj的原型是否有原型。若是沒有,則查找終止。
5.若是obj的原型上上面有它本身的原型,那麼繼續在obj的原型的原型上繼續查找。函數
幾乎每個js對象都有原型,可是有個例外。性能
let a = Obeject.crate(null) let b = {}
當Object.create()傳入null的時候, 返回一個真正的空對象a。這個對象不一樣於b,a對象上什麼都沒有,可是b對象上還有一個__proto__指向Object.prototype。this
function Man(name){ this.name = name } Man.prototype.setName = function(name){ this.name = name } let a = new Man("lee") console.log(a)
輸出以下:spa
實例化的對象a中 有兩個屬性一個是name,還有一個就是它的原型__proto__。而這個__proto__是指向a 這個對象的構造函數 (a.__proto__.constructor 就是a這個對象的構造函數,也就是Man這個函數。) 的原型的。而且,修改對象的__proto__是不推薦的作法,對於性能的影響可能有時候咱們不能不重視。而在Man的這個函數的prototype上面咱們定義了一個setName的屬性。
因此按照上面的查找流程,咱們在a對象的原型上找到了setName屬性。prototype
let animal = { weight:20, setWeight:function(weight){ this.weight = weight } } function Cat(name){ this.name = name } cat.prototype = animal
如上,只需簡單將函數的prototype指向一個對象,就完成了對這個的對象的繼承。如今全部經過new Cat()建立的對象都共享這個animal對象裏面的屬性。
這一點和直接使用Object.create()函數的繼承方式很像。code
另一種繼承方式,也是比較受開發者承認,相似於下面這種:對象
function Animal(weight){ this.weight = weight } Animal.prototype.setWeight = function(weight){ this.weight = weight } function Cat(name,weight){ Animal.call(this,weight) this.name = name } //同時,咱們別忘了,將Cat的prototype設爲Animal的prototype,這樣就完成了對Animal的繼承。 Cat.prototype = Object.create(Animal.prototype) Cat.prototype.constructor = Cat
ES6 中出現了類的語法糖,咱們寫繼承就更簡便了。繼承
最後附上一張原型鏈的解析圖:ip