簡單理解就是原型組成的鏈,對象的__proto__它的是原型,而原型也是一個對象,也有__proto__屬性,原型的__proto__又是原型的原型,就這樣能夠一直經過__proto__想上找,這就是原型鏈,當向上找找到Object的原型的時候,這條原型鏈就算到頭了。app
全部原型鏈屬性傳遞方向 (某個屬性在本對象中找不到時候,會到原型鏈上去找): 先找對象 自己屬性 =》構造函數的prototype中屬性 =》Object.prototype中的屬性=》null (結束)函數
function Person(){ this.name = name; this.age = age; } Person.prototype.talk = function(){ console.log("hello"); } let ming = new Person("ming",24);//ming === {name:"ming",age:24} ming.talk(); // ming中沒有talk這個屬性,就會經過__proto__到到原型鏈中去找,ming.__proto__ === Person.prototype。 //因爲ming.__proto__也就是 Person.prototype 也是一個對象,因此 ming.__proto__.__proto__ === Object.prototype。(若是ming.__proto__中沒有找到talk屬性會繼續向上找ming.__proto__.__proto__ ,直到找到最頂層null)
經過一個構造函數建立出來的多個實例,若是都要添加一個方法,給每一個實例去添加並非一個明智的選擇。這時就該用上原型了。this
在實例的原型上添加一個方法,這個原型的全部實例便都有了這個方法。
例子:給全部的function 添加一個 before屬性 和 after屬性prototype
Function.prototype.before = function(beforeFn){ let functionObj = this; return function (){ beforeFn.apply(this,arguments); functionObj.apply(this,arguments); } } Function.prototype.after = function(afterFn){ let functionObj = this; return function (){ functionObj.apply(this,arguments); afterFn(); } } function test(){ console.log('this is a test function!'); } let test1 = test.before(function(){ console.log(arguments); console.log('before'); }).after(()=>{ console.log('after'); }); test1();
//例子1 function Animal (){ this.speak = function(){}//第一種,直接將方法寫入構造函數中 } Animal.prototype.speak = function(){};//第二種將方法寫到原型鏈中 let dog1 = new Animal(); let dog2 = new Animal(); console.log (dog1.speak === dog2.speak) //第一種,返回false,第二種返回true
總結:假如將方法寫入構造函數中,每一次實例化都會去建立這樣一個功能徹底相同的函數,會很是耗費內存,而寫入原型鏈中只會建立一次,因此建議一般狀況下將實例方法寫到原型鏈中。code