先給出名詞的定義:
1、實例對象-被new出來對象稱之為實例對象
例如: const p1 = new Person()
p1就是實例對象
2、普通對象-未經new,直接聲明的對象是普通對象
例如:const p2 = { name: "John" }
p2就是普通對象
3、prototype, 中文翻譯:原型對象
4、__proto__ ,中文翻譯:原型 (英文可以讀作dunder proto)
由於原型對象和原型容易混淆,下文直接使用prototype 和 _proto(__proto__的簡寫)來行文,
為什麼要了解js中的原型鏈:
JS中沒有類的概念,為了實現繼承(讓一個實例對象擁有不屬於自身的屬性或方法),通過 __proto__將實例對象和實例對象的prototype聯繫起來組成原型鏈,就可以讓對象訪問到不屬於自己的屬性。
也就是説訪問一個實例p1的方法A,這個實例p1上不存在,則通過p1.__proto__上溯到p1構造函數Person的prototype(即上溯到Person.prototype),如果Person.prototype上依然沒找到方法A,則在Person.prototype的_proto上繼續找,通過Person.prototype.__proto__繼續上溯(Person.prototype.proto === Object.prototype)...
看下面的代碼
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`Hello, ${this.name}!`);
}
const p1 = new Person("Mike");
p1.sayHello(); // "Hello, Mike!"
console.log("Person.prototype->", Person.prototype);
console.log("p1.__proto__->", p1.__proto__);
console.log("getPrototypeOf(p1)->", Object.getPrototypeOf(p1));
console.log(Person.prototype === p1.__proto__); // true
上面這段代碼的結果展示了:
對於一個構造函數,和通過構造函數new出來的對象,構造函數的prototype與實例對象的_proto相同。
注:
__proto__是非標準的屬性,未在ECMAScript 6標準中定義,但幾乎所有的現代瀏覽器都支持 __proto__屬性。為了標準性,可以使用 Object.getPrototypeOf(obj) 方法來獲取對象的_proto。
再看下面這段代碼
const p2 = { name: "John" };
console.log(p2.__proto__); // [Object: null prototype] {} -> 是一個空對象{} console.log(p2.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
普通對象的_proto值是 [Object: null prototype] {}
Object.prototype.__proto__ === null 這是原型鏈的重點
那麼構造函數與Object有什麼關聯?
console.log(Person.prototype.__proto__ === Object.prototype); // true
其他:
1、prototype屬性只存在於函數上,而__proto__ 存在於所有對象上。
留2個問題
console.log(Object.__proto__ === Object.prototype); // true or false? why?
console.log(Function.__proto__ === Function.prototype); // true or false?
同步更新到自己的語雀
https://www.yuque.com/dirackeeko/blog/bggcmd8fcib3uyvt