1. 程式人生 > >js 原型鏈 __proto__ prototype

js 原型鏈 __proto__ prototype

原型鏈

在建立一個函式時,就自動為該函式新增一個prototype屬性,

該屬性指向原型物件,預設情況下,該物件中只包塊一個constructor屬性,

它是一個指向prototype屬性所在函式的指標。

var Person = function () {};

var p = new Person();

我們來看看這個new究竟做了什麼?我們可以把new的過程拆分成以下三步:

<1> var p = {}; //建立一個空物件p
<2> p.__proto__ = Person.prototype; //修改p的__proto__屬性指向,指向Person的prototype
<3> Person.call(p); //修改Person物件的this指標,指向物件p
下面來個例子理解下所謂的原型鏈
var Person = function(name){
    this.name = name;
}

Person.prototype.say = function(){
    alert(this.name);
}

var p = new Person('Jack');
p.say();


可以看到物件p的__proto__指標指向了Person.prototype,Person.prototype的__proto__又指向Object.prototype,而Object.prototype的__proto__為null,原型鏈結束。

原型鏈通過__proto__維繫

那麼__proto__是什麼?

每個物件都會在其內部初始化一個屬性,就是__proto__,當我們訪問一個物件的屬性時,如果這個物件內部不存在這個屬性(本地屬性),那麼它就會去__proto__裡找這個屬性。而這個__proto__同樣是一個物件,又會有自己的__proto__,於是就這樣一直構造下去,直到最後一個物件的__proto__屬性為null,就形成了我們平時所說的原型鏈。

查詢順序

每個物件都有一個原型物件,由於原型物件本身也是物件,根據上邊的定義,它也有自己的原型,而它自己的原型物件又可以有自己的原型,這樣就組成了一條鏈,這個就是原型鏈。JavaScritp引擎在訪問物件的屬性時,如果在物件本身中沒有找到,則會去原型鏈中查詢,

如果找到,直接返回值,如果整個鏈都遍歷且沒有找到屬性,則返回undefined.原型鏈一般實現為一個連結串列,這樣就可以按照一定的順序來查詢

tip:

如果原型鏈,本地屬性有相同的方法,那麼會優先在本地查詢並執行,原型鏈上的方法就不執行了。同樣的,屬性的查詢也是這麼個順序。

下面通過兩個小例子說明屬性和方法查詢順序:

1>

function Foo() {
    this.say = function(){
        alert('本地方法');
    }
}
A.prototype.say = function() {
    alert('prototype方法');
}
new Foo().say();
很顯然,alert出來的結果肯定是“本地方法”這條資訊,這說明了屬性和方法的查詢是從本地開始的。

2>

var base = {  
    name : "base",  
    getInfo : function(){  
       return this.id + "," + this.name;  
    }  
}  
    
var ext = {  
    id : 0,  
    __proto__ : base  
}  
    
console.log(ext.getInfo());// 0,base

//

var base = {  
    name : "base",  
    getInfo : function(){  
       return this.id + "," + this.name;  
    }  
}  
    
var ext = {  
    id : 0,  
    name : "ext",
    __proto__ : base  
}  
    
console.log(ext.getInfo());// 0,ext
前者結果為"0, base",ext中沒找到name屬性,就通過__proto__構成的原型鏈找到了base身上,正好base中有該屬性,結果為"base"。

後者結果為"0,ext",那是因為首先在ext中找到了屬性name,結果為"ext"。這裡要注意的是,ext在呼叫base中的getInfo時,this指向的其實是ext物件,而不是base,因此得到的結果才會是"ext"。