[JavaScript 學習筆記] 2. 繼承

繼承

許多 OO 語言支持兩種繼承方式:接口繼承和實現繼承。接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。如前所述,因爲函數沒有簽名,在 ECMAScript 中沒法實現接口繼承。 ECMAScript 只支持實現繼承,並且其實現繼承主要是依靠原型鏈來實現。app

原型鏈

基本思想是:利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。
構造函數、原型和實例的關係:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。函數

jsfunction SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

//繼承了 SuperType
SubType.prototype = new SuperType();

SuperType.prototype.getSubValue = function() {
    return this.subproperty;
}

var instance = new SubType();
alert(instance.getSuperValue());//true

  1. 別忘記默認的原型this

  2. 肯定原型和實例的關係spa

    jsalert(instance instanceof Object); //true
    alert(instance instanceof SuperType); //true
    alert(instance instanceof SubType); //true
    jsalert(Object.prototype.isPrototypeOf(instance));//ture
    alert(SuperType.prototype.isPrototypeOf(instance));//ture
    alert(SubType.prototype.isPrototypeOf(instance));//ture
  3. 謹慎地定義方法prototype

    給原型添加方法的代碼必定要放在替換原型的語句以後。指針

    jsfunction SuperType() {
    this.property = true;
    }
    
    SuperType.protype.getSuperValue = function() {
    return this.property;
    }
    
    function SubType() {
    this.subproperty = false;
    }
    //繼承了 SuperType
    SubType.prototype = new SuperType();
    //添加新方法
    SubType.prototype.getSubValue = function() {
    return this.subproperty;
    };
    //重寫超類型中的方法
    SubType.prototype.getSuperValue = function() {
    return false;
    };
    
    var instance = new SubType();
    
    alert(instance.getSuperValue());//false
    jsfunction SuperType() {
    this.property = true;
    }
    
    SuperType.prototype.getSuperValue = function() {
    return this.property;
    }
    
    function SubType() {
    this.subproperty = false;
    }
    
    //繼承了 SuperType
    SubType.prototype = new SuperType();
    
    //使用字變量添加新方法,會致使上一行代碼無效
    SubType.prototype = {
    getSubValue : function() {
        return this.subproperty;
    },
    someOtherMethod = function() {
        return false;
    }
    };
    
    var instance = new SubType();
    alert(instance.getSuperValue()); //error 原型鏈被切斷(如今的原型包含的是 Object 的實例)。

4.原型鏈的問題code

最主要的問題來自包含引用類型值的原型。前面已經介紹過包含引用類型值的原型屬性會被全部實例共享,這也是爲何要在構造函數中而不在原型對象中定義屬性的緣由。
第二個問題是:在建立子類型的實例時,不能向超類型的構造函數中傳遞參數。實際上,應該說是沒有辦法在不影響全部對象實例的狀況下,給炒類型的構造函數傳遞參數。對象

借用構造函數(僞造對象或經典繼承)

即在子類型構造函數的內部調用超類型構造函數。函數只不過是在特定環境中執行代碼的對象,因此可經過 apply()call() 方法也能夠在(未來)新建立的對象上執行構造函數。blog

jsfunction SuperType() {
    this.colors = ["red","blue","green"];
}

function SubType() {
    //繼承了 SuperType
    SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"

傳遞參數繼承

jsfunction SuperType(name) {
        this.name = name;
    }

    function SubType() {
        //繼承了 SuperType,同時還傳遞了參數
        SuperType.call(this,"PaddingMe");

        //實例屬性
        this.age = 25;
    }

    var instance = new SubType();

    alert(instance.name); //"PaddingMe"
    alert(instance.age); //25

組合繼承(僞經典繼承)

即將原型鏈和借用構造函數的方法組合在一塊兒,思路爲使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數來實現對實例屬性的繼承。

jsfunction SuperType(name) {
        this.name = name;
        this.colors = ["red","blue","green"];
    }

    SuperType.prototype.sayName = function() {
        alert(this.name);
    }

    function SubType() {
        //繼承屬性
        SuperType.call(this,name);

        this.age = age;
    }

    SubType.prototype = new SuperType();
    SubType.prototype.constuctor = SubType();
    SubType.prototype.sayAge = function() {
        alert(this.age);
    }

    var instance1 = new("PaddingMe",25);
    instance1.colors.push("black");
    alert(instance1.colors); //"red,blue,green,black"
    instance1.sayName; //"PaddingMe"
    instance1.sayAge; //25


    var instance2 = new("hw",26);
    alert(instance2.colors); //"red,blue,green"
    instance2.sayName; //"hw"
    instance2.sayAge; //26

原型式繼承

jsfunction object(o) {
        function F(){}
        F.prototype = o;
        return new F();
    }
    var person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }

    var antherPerson = object(person);
    antherPerson.name = "Hhb";
    antherPerson.friends.push("zxp");

    var yetAntherPerson = object(person);
    yetAntherPerson.name = "Linda";
    yetAntherPerson.friends.push("him");

    alert(person.friends)//"hw,wjj,hz,zxp,him"

ECMAScirpt 5 中新增 Object.create() 方法規範化了原型式繼承。有兩個參數,一個用做新對象原型的對象和(可選的)一個爲新對象定義額外屬性的對象。

在傳入一個參數狀況下,Objetc.create() 和 object() 方法的行爲相同。

jsvar person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }
    var antherPerson = Object.create(person);
    antherPerson.name = "Hhb";
    antherPerson.friends.push("zxp");

    var yetAntherPerson = Object.create(person);
    yetAntherPerson.name = "Linda";
    yetAntherPerson.friends.push("him");

    alert(person.friends)//"hw,wjj,hz,zxp,him"

第二個參數與 `Object.defineProperties() 方法的第二個參數格式相同: 每一個屬性都是經過本身的描述符定義的。

jsvar person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }

    var anthorPerson = Object.create(person, {
        name: {
            value:"hehe";
        }
    })

    alert(anthorPerson.name);//"hehe"

寄生式繼承

即建立一個僅用於封裝繼承構成的函數,該函數在內部以某種方式來加強對象,最後再像真地是它作了全部工做同樣返回對象。

jsfunction createAnother(original) {
        var clone = object(original); //經過調用函數建立一個新對象
        clone.sayHi = function() { //以某種方式來加強這個對象
            alert("hi");
        };
        return clone; //返回這個對象
    }

    var person = {
        name : "PaddingMe";
        friends :["hw","wjj","hz"];
    }

    var anthorPerson = createAnother(person);
    anthorPerson.sayHi();//"hi"

寄生組合式繼承

jsfunction SuperType(name) {
    this.name = name;
    this.colors = ["red","blue","green"];
}

SuperType.prototype.sayName = function() {
    alert(this.name);
}

function SubType(name,age) {
    SuperType.call(this,name); //第二次調用SuperType();

    this.age = age;
}

SubType.prototype = new SuperType(); // 第一次調用SuperType();

SubType.prototype.constuctor = SubType;

SubType.prototype.sayAge = function(){
    alert(this.age);
}

所謂寄生組合式繼承,即經過借用構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法。基本思路爲:沒必要爲了指定子類型的原型而調用超類型的構造函數,咱們所須要的無非是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,而後再將結構指定給子類型的原型。寄生組合式繼承的基本模式:

jsfunction inheritPrototype(subType,superType){
        var prototype = object(superType.prototype); //建立對象
        prototype.constructor = subType; //加強對象
        subType.prototype = prototype; // 指定對象
    }
jsfunction SuperType(name) {
    this.name = name;
    this.colors = ["red","blue","green"];
}

SuperType.prototype.sayName = function() {
    alert(this.name);
}

function SubType(name,age) {
    SuperType.call(this,name); //第二次調用SuperType();

    this.age = age;
}

inheritPrototype(SubType,SuperType);

SubType.prototype.sayAge = function(){
    alert(this.age);
}
相關文章
相關標籤/搜索