本文章僅針對我自己在看書過程中對一些不太清楚的知識點進行查漏補缺——《你不知道的JavaScript(上卷)》第二部分this和原型中的第5章”原型“
原型概念
JavaScript中每個對象都有一個特殊的内置屬性prototype,這個特殊的對象可以指向另一個對象
觸發[[get]]操作時,如果在對象上沒有找到需要的屬性或者方法引用,引擎就會繼續在 [[Prototype]] 關聯的對象上進行查找
擷取原型的方式
- 通過對象的__proto__屬性可以擷取到(早期浏覽器自己添加的,存在一定的相容性問題)
- 通過Object.getPrototypeOf方法
prototype與__proto__
prototype
特點:所有函數都有prototype屬性,而對象沒有
函數的prototype中有屬性constructor,這個屬性指向函數,即
function fn(){}
fn.prototype.constructor === fn
也可以嵌套循環調用 【fn.prototype.constructor.prototype.constructor...】
__proto__
特點:所有的對象都有__proto__屬性,當然也包括函數
new關鍵字建立一個變量發生了什麼
function Person() {}
var p = new Person();
// 上面的操作相當于會進行如下的操作
// 1. 建立一個全新的變量
p = {}
// 2. 函數的顯示原型會指派給這個對象的隐式原型
p.__proto__ = Person.prototype
// 3. 這個新建立的對象綁定到函數調用的this上
// 4. 執行函數
// 5. 如果函數沒有傳回值,便傳回這個新建立的秀
一張圖了解普通函數、Function、Object 與它們建立的對象、它們的原型對象之間的關系

function Foo() {}
new Foo().__proto__ === Foo.prototype
new Function().__proto__ === Function.prototype
new Object().__proto__ === Object.prototype
Foo.__proto__ === Function.prototype
Function.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
Foo.prototype.__proto__ === Object.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
原型鍊的盡頭——Object的原型
Object.getPrototypeOf({}) // [Object: null prototype] {}
Object.getPrototypeOf(Object.getPrototypeOf({})) // null
原型鍊的作用
通路變量或方法
本質:觸發[[get]]操作時,先找這個對象上,沒有就找原型對象
例子:for in 、 in 、 a[key]、a.key
複雜情景
myObject.foo = "bar";
- myObject對象包含foo屬性(writable為true),修改已有的foo屬性值,無論原型鍊上是否有
- foo不存在于myObject中,周遊原型鍊,如果原型鍊上沒有該屬性,則指派到myObject上
- foo不存在于myObject中,存在于其原型鍊上
- 沒有被标記為隻讀,直接在 myObject 中添加一個名為 foo 的新屬性
- 隻讀,嚴格模式下報錯,非嚴格模式這條指派語句不起作用
- 有setter,則調用這個setter,foo不會被添加到myObject上,也不重新定義setter
繼承
Object.create(o)
作用:建立一個新對象并把它關聯到我們指定的對象
原理:借用構造函數實作繼承
實作:
if (!Object.create) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
拓展:如果僅僅想要處理方法或者屬性未找到時的場景,可以使用Proxy
Object.setPrototypeOf(o1, o2)
作用:
原理:相當于直接設定隐式原型,即o1.__proto__ = o2
應用——vue中的inject/provide
vue中的inject與provide提供了一種後代與祖先元件的通信方式
provide(key, value)提供一個值,可以被後代元件引用
inject(key)用來通路祖先元件提供的值,沿着父元件鍊查找,這個父元件鍊的實作就是原型鍊