原型
概念
- 無論什麼時候,只要建立了一個函式,那麼就會為之建立一個
prototype
屬性,這個屬性指向了函式的原型物件。
- 在預設情況下,每個原型物件同樣會建立一個
constructor
屬性,用於指向prototype
屬性所在函式的指標。
- 使用建構函式建立的物件,會建立一個名為
[[prototype]]
的指標指向建構函式的原型物件。
三個屬性
prototype
:每一個函式都有一個prototype
屬性,指向原型物件。
- 例外:
Function.prototype.bind()
沒有prototype
屬性
[[prototype]
:每一個例項物件都有一個[[prototype]]
內部屬性,指向建構函式的原型物件。
constructor
:每一個原型物件都有一個constructor
屬性,指向關聯的建構函式。
舉個?
- 建立了一個函式後,預設情況下,其原型物件只獲得一個
constructor
屬性,該屬性指向Person
函式。
function Person() {}
console.log(Person.prototype);
複製程式碼
function Person() {}
Person.prototype.country = 'China';
Person.prototype.sex = 'man';
Person.prototype.age = 26;
Person.prototype.sayAge = function() {
console.log(this.age);
}
console.log(Person.prototype);
複製程式碼
- 每個物件例項都有一個
__proto__
屬性去訪問原型物件,這裡的__proto__
屬性是瀏覽器提供用於訪問例項物件內部屬性[[prototype]]
。ECMAScript5中增加了一個Object.getPrototypeOf()
方法,用於物件訪問其原型物件。
function Person() {}
Person.prototype.country = 'China';
Person.prototype.sex = 'man';
Person.prototype.age = 26;
Person.prototype.getAge = function() {
console.log(this.age);
}
var person1 = new Person();
person1.getAge();
console.log(person1);
var person2 = new Person();
person2.getAge();
console.log(person2);
複製程式碼
- 它們之間的關係如下圖:
- 由於原型物件會共享自身的屬性和方法,因此這裡建立的2個Person物件例項能夠直接訪問
getAge()
- 當呼叫
person1.getAge()
時,會先在person1例項中搜尋getAge()
,若找到就返回;若沒有找到,則到person1的原型物件中去搜尋。這裡進行了2次搜尋工作。
- 若在例項物件中新增了原型物件中同名的屬性,那麼該屬性並不會重寫原型物件中的值,只是作為例項物件自己的屬性,不會被共享。例如:
function Person() {}
Person.prototype.country = 'China';
Person.prototype.sex = 'man';
Person.prototype.age = 26;
Person.prototype.getAge = function() {
console.log(this.age);
}
var person1 = new Person();
person1.age = 28;
console.log(person1);
複製程式碼
- 可以看出:只是為person1物件新增了一個
age
屬性,而原型物件中的age
屬性的值不改變。
console.log(person1.age)
會輸出28,而不是26。此時訪問的是person1物件中的age
屬性。可以使用delete person1.age
刪除本物件上的屬性,刪除之後訪問的就是原型物件上面的age
屬性了。
- 可以使用
hasOwnProperty()
來檢測一個屬性是存在於物件例項中,還是原型物件中。
原型鏈
概念
- 當一個例項物件的原型物件是另一種型別的例項物件,且這個例項物件的原型物件同樣又是另一種型別的例項物件,以此下去,最終會就形成了一個有限的原型鏈。
- 原型鏈是JavaScript中一種能夠實現繼承的方式。
舉個?
function Animal() {}
Animal.prototype.category = 'Animal';
function Cat() {}
Cat.prototype = new Animal();
Cat.prototype.category = 'Cat';
function Tiger() {}
Tiger.prototype = new Cat();
Tiger.prototype.category = 'Tiger';
var tiger = new Tiger();
console.log(tiger);
複製程式碼
- tiger指向Tiger的原型,Tiger的原型指向Cat的原型,Cat的原型指向Animal的原型,Animal的原型指向Object的原型。
- 簡單來說:
__proto__
屬性連線每個物件,形成了原型鏈。任何原型鏈的最底層都是Object.prototype
。
- 注意:Tiger例項物件和Cat例項物件的原型物件都沒有
constructor
屬性,這是因為我們重寫了原型物件,將其賦值為了使用new
建立的新物件。