不會JS中的OOP,你也太菜了吧!(第二篇)


一、你必須知道的

1> 原型及原型鏈在繼承中起到了關鍵的作用。所以你一定要理解他們。
2> 不會JS中的OOP,你也太菜了吧!(第一篇)

 

二、繼承的6種方法

1> 原型鏈繼承

原型鏈繼承是通過創建Super的實例,並將該實例賦值給Sub.prototype來實現的。

實現的本質是:重寫子類型的原型對象,代之以超類型的實例。

function Super(){
    this.name = 'JChen___';
}
Super.prototype.getSuperName = function(){
    return this.name;
}

function Sub(){
    this.subname = 'JChen___son';
}
Sub.prototype = new Super(); //原型繼承體現在這里
Sub.prototype.getSubName = function(){
    return this.subname;
}

var instance = new Sub();

注意:此時instance.constructor現在指向的是Super的,這是因為Sub.prototype指向了Super.prototype,而Super.prototype.constructor = Super。

原型鏈的問題:類似於利用原型創建對象,原型共享的特性也是原型鏈繼承的最大問題。

 

2> 借用構造函數繼承

在解決原型中包含引用類型值所帶來的問題的過程中,我們開始使用一種叫做借用構造函數的技術。

這種技術的基本思想相當簡單:在子類型構造函數的內部調用超類型構造函數

這樣一來,就會在新子類對象上執行超類函數中定義的所有對象初始化代碼。結果,每個子類的實力都會有自己的超類中屬性的副本了。

function Super2(name){
    this.colors = ['red', 'blue'];
    this.name = name;
}

function Sub2(){
    Super2.call(this, 'JChen___2'); //借用構造函數技術體現在這里 this.age = 29;
}

var instance1 = new Sub2();
instance1.colors.push('black');
var instance2 = new Sub2();
instance2.colors.push('green');

借助構造函數繼承的問題:

1): 方法都在構造函數中定義,無法復用。

2): 在超類型的原型中的方法對子類是不可見的。

 

3> 組合繼承(原型+借用構造)

組合繼承指的是將原型鏈和借用構造函數的技術組合到一塊,從而發揮二者之長的一種繼承模式。

組合繼承的思路:使用原型鏈實現對方法和屬性的繼承,通過借用構造函數實現對實例屬性的繼承。

function Super3(name){
    this.name = name;
    this.colors = ['red', 'blue'];
}
Super3.prototype.sayName = function(){
    return this.name;
}

function Sub3(name, age) {
    Super3.call(this, name);
    this.age = age;
}
Sub3.prototype = new Super3(); //解決借用構造函數技術的缺點
Sub3.prototype.constructor = Sub3; //糾正原型繼承改變了的構造函數
Sub3.prototype.sayAge = function(){
    return this.age;
}

組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,成為JavaScript中最常用的繼承模式。

組合繼承的問題:兩次調用超類構造函數。

 

4> 原型式繼承

原型式繼承的思路:借助原型可以基於已有的對象創建新對象,同時還不必因此創建自定義類型。

function object(o){ //原型式繼承的關鍵
    function F(){}
    F.prototype = o;
    return new F();
}
var person = {
    name: 'JChen___4',
    colors: ['blue']
}
var person1 = object(person);
person1.name = 'JChen___4___2'
person1.colors.push('red');
var person2 = object(person);
person2.name = 'JChen___4___3';
person2.colors.push('green');

原型式繼承的問題:同原型鏈一樣,他也有共享的劣勢。

 

5> 寄生式繼承

寄生式繼承的思路:創建一個僅用於封裝繼承過程的函數,該函數內部以某種方式來增強對象,最后再返回該對象

function createAnother(origin){ //寄生式繼承的關鍵
    var clone = object(origin);
    clone.sayHi = function(){
        return 'Hi';
    };
    return clone;
}
var person = {
    name: 'JChen___4',
    colors: ['blue']
}
var person1 = createAnother(person);

寄生式繼承的問題:像構造函數一樣,由於不能做到函數的復用而降低效率。

 

6> 寄生組合式繼承

寄生組合式繼承:通過借用構造函數來借用屬性,通過原型鏈的混成形式來繼承方法。

其背后的思想是:不必為了指定子類型的原型而調用超類型的構造函數,我們需要的無非就是超類型的一個副本而已。

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
function inheritProto(subType, superType){ //避免第一調用構造函數的關鍵
    var proto = object(superType.prototype);
    proto.constructor = subType;
    subType.prototype = proto;
}

function Super6(name){
    this.name = name;
    this.colors = ['red', 'blue'];
}
Super6.prototype.sayName = function(){
    return this.name;
}

function Sub6(name, age){
    Super6.call(this, name);
    this.age = age;
}

inheritProto(Sub6, Super6);

Sub6.prototype.sayAge = function(){
    return this.age;
}

var instance1 = new Sub6('JChen___6', '12');
instance1.colors.push('black');

開發人員普遍認為寄生組合式繼承是引用類型最理想的繼承范式。

 

三、總結

這就是JavaScript中的6種繼承方式,如果大家能夠畫出每個繼承的原型鏈關系圖,那么繼承就是小菜一碟了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM