一、要了解原型鏈,首先要了解什麼是原型、以及有什麼作用
我們建立的每個函式都有一個prototype屬性(即原型物件指標),並且每個原型物件上都有一個constructor屬性,該屬性的指標指向原型物件所在的函式(函式本身)
function Example(){}
var example = new Example();
example.prototype.constructor==Example //true
複製程式碼
使用原型的好處就是方便我們建立讓所有物件例項都能共享屬性和方法
// 建立一個建構函式
function People(){}
People.prototype.name = '路人甲';
People.prototype.age = '29';
People.prototype.getInfo = function(){
return this.name+'今年'+this.age+'歲了';
}
var people1 = new People(); //例項1
people1.getInfo();  //列印出'路人甲今年29歲了'
var people2 = new People(); //例項2
people2.getInfo(); //列印出'路人甲今年29歲了' 
複製程式碼
當一個建構函式建立一個例項後,物件例項有一個內部指標(proto)指向建構函式的原型物件
function Person(){} // 建立一個建構函式
var p = new Person(); //此處p是建構函式Person的例項
p.__proto__ == Person.prototype //true,
// (注:由於__proto__屬性是非標準的,建議使用isPrototypeOf或 Object.getPrototypeOf方法驗證)
Person.prototype.isPrototypeOf(p); //true
Object.getPrototypeOf(p)==Person.prototype; //true
複製程式碼
二、通過上面的說明,我們已經對原型有一些瞭解了,那麼什麼是原型鏈呢?
原型鏈簡單點說,就是一個建構函式的例項通過賦值的方式賦給另一個函式的原型物件(prototype)實現的
// 建立一個建構函式A
function A(){}
A.prototype.run = function(){
return '我叫蠟筆小新,今年5歲';
}
// 建立一個建構函式B
function B(){}
//通過賦值的方式使建構函式B擁有了建構函式A的方法(也就是說存在於A例項中的所有屬性和方法,也存在於B中了)
B.prototype = new A();
var b = new B();
b.run(); //列印出'我叫蠟筆小新,今年5歲';
複製程式碼
當例項呼叫某個屬性或方法的時候會執行一次查詢,比如呼叫b.run()時候,會先執行三次查詢:例項b->B.prototype->A.prototype,最後一步才找到該方法。
前面說過例項物件有一個內部指標指向建構函式的原型物件,那麼我們可以使用例項的內部指標(proto)來進一步瞭解原型鏈
b.__proto__ == B.prototype //true
// 因為B.prototype繼承了建構函式A,所以我們也能獲取到建構函式A的原型物件
b.__proto__.__proto__ == A.prototype ; //true
B.prototype.__proto__ == A.prototype; //true
// 在js中所有的引用型別都是Object的例項,故此我們可以可以根據原型鏈找到Object的原型物件(所有函式的預設原型都是Object的例項)
b.__proto__.__proto__.__proto__ == Object.prototype //true
B.prototype.__proto__.__proto__ == Object.prototype //true
A.prototype.__proto__ == Object.prototype //true
複製程式碼