JS原型鏈的理解
阿新 • • 發佈:2018-11-28
一、原型鏈
- 先來捋一捋建構函式、原型和例項的關係
- 在JavaScript中,所有的函式都有
prototype
**(顯式原型)**屬性,這個屬性指向一個物件,即原型物件。 - 原型物件中又包含一個指標(就是constructor),它指向原型物件所屬的建構函式。
- 每個例項物件都有一個
__proto__
**(隱式原型,這個屬性官方定義為:[[prototype]]
)**屬性,這個屬性指向建構函式的原型物件。來看下程式碼,解釋我所說的幾點:
function Person(){
this.name = [];
this.say = function() {
console.log(this.name);
}
}
var jack = new Person(); // 建立一個Person例項
jack.name.push('jack');
console.log(jack.name);
jack.say();
console.log(Person.prototype.constructor === Person); // true
// 例項物件的 constructor 屬性是從建構函式的原型物件中繼承過來的。
console.log(jack.constructor === Person); // true
console. log(jack.__proto__ === Person.prototype) // true
- 弄清楚建構函式、原型和例項的關係之後,我們進入正題:原型鏈
原型鏈說白了就是例項物件和原型物件之間實現屬性共享和繼承的紐帶吧,環環相扣像鏈條一樣。
來看下程式碼
function Grand() {
this.name = "grandpa";
}
Grand.prototype.sayName = function() {
console.log(this.name);
}
Grand.prototype.hobby = function() {
console. log("play chess");
}
function Father() {
this.name = "father";
}
Father.prototype = new Grand();
Father.prototype.hobby = function() {
console.log("programme");
}
function Son() {
this.name = "son";
}
Son.prototype = new Father();
Son.prototype.hobby = function() {
console.log("王者榮耀");
}
var grand = new Grand();
var father = new Father();
var son = new Son();
grand.sayName(); // grandpa
grand.hobby(); // play chess
father.sayName(); // father
father.hobby(); // programme
son.sayName(); // son
son.hobby(); // 王者榮耀
我來解釋下上述程式碼:
首先,有三個建構函式,Grand,Father和Son.我們讓 Father.prototype = new Grand();
來實現Father對Grand的繼承,通過 Son.prototype = new Father();
來實現Son對Father的繼承。這樣Father 和 Son的例項就能夠訪問到Grand原型上的方法。
訪問hobby方法的過程:
-
在例項物件father和son中都有一個
__proto__
屬性,這個屬性指向各自的建構函式的原型物件。當我們通過son.hobby()
來訪問hobby這個方法時,它首先會在自己身上找,看有沒有這個方法,沒有就進行下一步: -
在
Son.prototype
上面找,看有沒有hobby這個方法,結果找到了,就可以呼叫該方法。
這裡我們是重寫了Grand原型物件中的hobby方法,當我們沒有從寫該方法時過程就是這樣的:
總結以下屬性尋找規則:
- 在訪問某個物件的某個屬性的時候,會首先在自己身上找是否存在該屬性;
- 如果在物件身上沒有該屬性,就會到該物件建構函式的原型物件上去找;
- 如果原型對像上還沒有,就到原型物件的原型上去找;
- 一直找到Object的原型物件的原型,即
Object.prototype.__proto__ = null
為止。