1.原型的定義
每一個對象從被創建開始就和另一個對象關聯,從另一個對象上繼承其屬性,這個另一個對象
就是?原型。
當訪問一個對象的屬性時,先在對象的本身找,找不到就去對象的原型上找,如果還是找不到,就去對象的原型(原型也是對象,也有它自己的原型)的原型上找,如此繼續,直到找到為止,或者查找到最頂層的原型對象中也沒有找到,就結束查找,返回undefined
。
這條由對象及其原型組成的鏈就叫做原型鏈。
總結:
- 原型存在的意義就是組成原型鏈:引用類型皆對象,每個對象都有原型,原型也是對象,也有它自己的原型,一層一層,組成原型鏈。
- 原型鏈存在的意義就是繼承:訪問對象屬性時,在對象本身找不到,就在原型鏈上一層一層找。說白了就是一個對象可以訪問其他對象的屬性。
- 繼承存在的意義就是屬性共享:好處有二:一是代碼重用,字面意思;二是可擴展,不同對象可能繼承相同的屬性,也可以定義只屬于自己的屬性。
2.原型鏈定義
每個對象都有一個內部屬性 [[Prototype]]
(可通過 __proto__
訪問),這個[[Prototype]]
指向它的原型對象(prototype
),這個原型對象也有自己的 __proto__
,一直向上查找,最終到達終點null
,形成原型鏈。
總結:
- 對象有
__proto__
屬性,函數有__proto__
屬性,數組也有__proto__
屬性,只要是引用類型,就有__proto__
屬性,指向其原型。 - 只有函數有
prototype
屬性,只有函數有prototype
屬性,只有函數有prototype
屬性,指向new
操作符加調用該函數創建的對象實例的原型對象。
實例代碼
function Person(name) {this.name = name;
}Person.prototype.sayHello = function() {console.log("Hello, I'm " + this.name);
};const p = new Person("Alice");p.sayHello(); // 從 p 找不到 sayHello,順著原型鏈找到 Person.prototype
p --> Person.prototype --> Object.prototype --> null
-
p.__proto__ === Person.prototype
-
Person.prototype.__proto__ === Object.prototype
-
Object.prototype.__proto__ === null
3.constructor
構造函數都有一個prototype
屬性,指向使用這個構造函數創建的對象實例的原型對象。
這個原型對象中默認有一個constructor
屬性,指回該構造函數。
Person.prototype.constructor === Person // true
4.應用
①.手寫實現instanceof
function instanceof2(L, R) {// 獲取 R 的 prototype.//R 是構造函數,我們要找的是它的 .prototype,這是構造出來對象的原型。let RP = R.prototype;// 獲取 L 的原型//取 L 的原型(注意是 __proto__,而不是 prototype),它表示當前對象的內部原型鏈引用。L = L.__proto__;// 遍歷 L 的原型鏈while (true) {if (L === null) { // 到頭了都沒找到,說明不是return false;}// 🔽 插入這行代碼if (L === RP) { // 找到了原型鏈中有構造函數的 prototypereturn true;}L = L.__proto__; // 繼續向上查找原型鏈}
}
instanceof
的本質:判斷某對象的原型鏈上是否能找到構造函數的.prototype
。-
__proto__
是對象的內部原型引用。 -
可以用
Object.getPrototypeOf(obj)
來代替__proto__
(更標準)。