從原型到原型鏈

構造函數

function Animal() {

}
var cat = new Animal();
cat.name = 'Tom';
console.log(cat.name) // Tom

prototype

每個函數都有一個 prototype 屬性
函數的 prototype 屬性指向了一個對象,這個對象正是調用該構造函數而創建的實例的原型,也就是這個例子中的 cat dog 的原型。

function Animal() {

}
// 雖然寫在註釋裏,但是需要注意:prototype是函數纔會有的屬性
Animal.prototype.name = 'Tom';
var cat = new Animal();
var dog = new Animal();
console.log(cat.name) // Tom
console.log(dog.name) // Tom

原型

每一個JavaScript對象(null除外)在創建的時候就會與之關聯另一個對象,這個對象就是我們所說的原型每一個對象都會從原型"繼承"屬性。

圖片描述

proto

如何表示實例與實例原型之間的關係呢,這裏需要提到 proto
每一個JavaScript對象(除了 null )都具有的一個屬性,叫__proto__,這個屬性會指向該對象的原型

  • 數組、正則、Math、Date、類數組等
  • 實例是對象數據類型的值
  • 函數的原型prototype屬性的值也是對象類型
  • 函數也是對象數據類型

每一個對象數據類型的值,都自帶__proto__屬性,這個屬性用來指向所屬類的原型prototype

function Animal() {

}
var cat = new Animal();
console.log(cat.__proto__ === Animal.prototype); // true

圖片描述

實例對象和構造函數都可以指向原型

constructor

每個原型都有一個 constructor 屬性指向關聯的構造函數

function Animal() {

}
console.log(Animal === Animal.prototype.constructor); // true

圖片描述

則可以得出

function Animal() {

}
var cat = new Animal();
console.log(cat.__proto__ == Animal.prototype) // true
console.log(Animal.prototype.constructor == Animal) // true
// 順便學習一個ES5的方法,可以獲得對象的原型
console.log(Object.getPrototypeOf(cat) === Animal.prototype) // true

實例和原型

當讀取實例的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層爲止。

function Animal() {

}

Animal.prototype.name = 'Tom';

var cat = new Animal();

cat.name = 'Jerry';
console.log(cat.name) // Jerry

delete cat.name;
console.log(cat.name) // Tom

我們給實例添加了name屬性,放我們打印cat.name時結果自然是Jerry。當我們刪除了cat的name屬性時,讀取cat.name時,從對象中無法找到name屬性,就會從cat的原型,也就是cat.__proto__,同時也是Animal.prototype中查找,找到結果爲Tom。

反問:假若沒有找到該怎麼辦呢?原型的原型又是誰呢?

原型的原型

原型對象其實就是通過Object構造函數生成的,實例的__proto__指向構造函數的prototype

圖片描述

原型鏈

提問:Object.prototype的原型呢?
是null,可以打印一下看看:

console.log(Object.prototype.__proto__ === null) // true
null 表示“沒有對象”,即該處不應該有值。

Object.prototype.__proto__的值爲null跟Object.prototype沒有原型,其實是一個意思。
查找屬性的時候查到Object.prototype就停止查找了。

圖片描述

圖中黃色的線就是相互關聯的原型組成的鏈狀結構——原型鏈

由於函數也是對象,會在內存中單獨開闢一個空間,因此,當實例對象多的時候,就會出現內存空間被很多重複的函數佔用。
如:有100個 Person 的實例對象,那麼在內存空間裏就會有100個eat方法佔用的空間,這些方法分別指向不同的實例對象。但是他們的執行結果卻都是一樣的。這就造成了內存空間的浪費!

爲解決這個問題,我們需要一個共享的空間,在裏面存放一些公共的方法,屬性,這就是原型。
JavaScript原型就是爲了實現對象之間的聯繫,解決構造函數無法數據共享而引入的一個屬性。原型鏈就是一個實現對象間聯繫即繼承的主要方法。


圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章