javascript 原型與原型鏈淺析

原型 和原型鏈

什麼是原型鏈

簡單理解就是原型組成的鏈,對象的__proto__它的是原型,而原型也是一個對象,也有__proto__屬性,原型的__proto__又是原型的原型,就這樣能夠一直經過__proto__想上找,這就是原型鏈,當向上找找到Object的原型的時候,這條原型鏈就算到頭了。app

原型與原型鏈的幾個要點
  • 每個函數都有一個prototype屬性 和 一個 __proto__屬性。
  • 每個對象都有一個__proto__屬性 。
  • (除null)全部的對象都是由構造函數建立的。
  • 對象的__proto__ === 該對象的構造函數的prototype ( [].__proto__ === Array.prototype)
  • 對象的__proto__ 也是一個對象,因此對象的__proto__的__proto__ === Object.prototype
  • null位於原型鏈最頂層
  • Function.__proto__ === Function.prototype。 這是一個先有蛋仍是先有雞的問題
  • null 沒有__proto__ 和 prototype
  • 全部原型鏈屬性傳遞方向 (某個屬性在本對象中找不到時候,會到原型鏈上去找): 先找對象 自己屬性 =》構造函數的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

一個原型與原型鏈的圖解

相關文章
相關標籤/搜索