原生的原型鏈html
function fn(){},fn 爲 Function的一個實例,原型鏈爲 null -> Object -> Function -> fn:函數
fn.__proto__ === Function.prototypethis
Function.prototype.__proto === Object.prototypees5
Object.prototype.__proto__ === nullprototype
原型鏈經過原型(prototype)連接,prototype 就是一個 只有(構造)函數纔有的特殊的實例,包含了constructor指針(和__proto__,全部實例都有)指針
以後new出來的普通實例(非prototype)都包含這個prototype(引用名爲__proto__):console.log(sonA) // {/* 其餘屬性 */ __proto__: Son.prototype}xml
舉例來講,對於函數實例,全部函數實例.__proto__ === Function.prototype (經過這個能拿到Function上的通用屬性,如bind函數)htm
甚至Function.__proto__ === Function.prototype, Object.__proto__ === Function.prototype 對象
Function instanceof Object // true Function.__proto__.__proto__ === Object.prototype (優先是更具體的函數,而後才做爲更抽象的對象,對象永遠在原型鏈較上層)blog
Object instanceof Function // true Object.__proto__ = Function.prototype
原型鏈繼承:
未繼承時
console.log(Son.prototype) // { constructor: Son, __proto__: Object.prototype }
原型鏈繼承了Father時,
console.log(Son.prototype) // { __proto__: Father.prototype }父類的一個實例, 經過new Father 或者 Object.create(Father.prototype)生成
須要手動賦予constructor:
Object.defineProperty(Son.prototype, "constructor", {
value: Son,
writable: false
});
console.log(Object.prototype)
{ __proto__: null }
原型鏈繼承,本質就是修改函數的prototype,使其從指向Function變爲指向父類;父類的對象恰好符合這個特性
鞏固一下上面的知識點,請判斷如下比較是否爲真:
Object.prototype.__proto__ === null
Object.__proto__ === Function.prototype
Function.__proto__ === Function.prototype
fn.__proto___ === Function.prototype
Object.prototype === Function.prototype.__proto__
Object.prototype === fn.prototype.__proto__
Object.prototype.isPrototypeOf(fn)
Object.prototype.isPrototypeOf(fn.prototype)
Function.prototype === fn.__proto__;
Function.prototype.isPrototypeOf(fn)
Function.prototype.isPrototypeOf(fn.prototype) // false
答案:以上判斷若未特殊說明,結果都爲真
談一下new
自定義原型鏈:基於原型鏈的繼承
Father() {} -> Son() {]
繼承的本質是,如何使Son的實例能訪問到Father定義的屬性
經過原型鏈,咱們將Son的原型指向Father
Son原型鏈如今是指向的Function,Son.__proto__ === Function.prototype
咱們但願Son.__proto__ === Father.prototype
按es5以前的規範,咱們不能直接訪問__proto__,那麼只能修改prototype (ES5中用Object.getPrototypeOf函數得到一個對象的[[prototype]]。ES6中,使用Object.setPrototypeOf能夠直接修改一個對象的[[prototype]])
咱們知道 Father的實例的__proto__指向Father.prototype,那麼Son.prototype等於Father的實例就能夠
Son.prototype = new Father() 或者
Son.prototype = Object.create(Father.prototype)
這裏有一個問題,prototype的constructor屬性應該指向構造函數,而這種寫法的constructor經過原型鏈會找到Father,因此須要定義一下constructor
Object.defineProperty(Son.prototype, "constructor", {
value: Son,
writable: false
});
順便了解一下原型鏈查找順序
優先查找對象的,對象上沒有則經過__proto__找prototype,還沒找到,就找prototype.__proto__, 也就是父類的prototype
好比
對象objA查找hasOwnProperty
objA -> Son.prototype -> Object.prototype -> Object.prototype.hasOwnProperty
函數funcA查找bind
funcA -> Function.prototype -> Function.prototype.bind
PS:對於 const fn = () => {} 這樣的箭頭函數,不屬於原型鏈的範疇 能夠參考 http://www.cnblogs.com/mengff/p/9656486.html