2016-07-07 28 views
1

與面向類的語言相比,JS基於原型,而對象的構造函數不僅包含「構造函數邏輯」(我在MDN中發現了這個術語),而且構造函數還定義了特權方法。在一個「類」是另一個類的孩子的情況下(遺憾的是,我不知道比JS的「類」更好的術語),這導致父類構造函數在子類能夠覆蓋之前執行的問題一個方法或者子類不能重寫一個方法,因爲構造函數還沒有運行。Javascript:如何在覆蓋子類中的繼承方法之後運行父類的構造函數邏輯?

我會舉一個例子來說明我的意思。假定在對象上定義了特權函數的「父類」以及調用此方法的構造函數邏輯。

function Parent() { 
    this.methodA = function() { 
    // do something 
    }; 

    // C'tor logic starts here 
    // Beside other things also call some method of this object 
    this.methodA(); 
} 

假設一個孩子的類,應重新定義methodA但仍使用父類的構造函數 邏輯。

第一種方法是在 子構造函數的開頭調用父構造函數。但是,父構造函數仍然調用父項的實現。

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

function Child() { 
    // Call parent constructor first. Problem: The parent constructor 
    // calls methodA before it will be overriden by child constructor 
    Parent.call(this); 

    var _oldMethodA = this.methodA; 
    this.methodA = function() { 
    // do something special and then call parent method 
    _oldMethodA.call(this); 
    }; 
} 

第二種方法是以後調用父構造,但是,然後 父方法不能被重寫。

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

function Child() { 
    // Override first. Problem: The parent constructor has not defined methodA 
    // yet, hence the line below fails. 
    var _oldMethodA = this.methodA; 
    this.methodA = function() { 
    // do something special and call parent method 
    _oldMethodA.call(this); 
    }; 

    Parent.call(this); 
} 

如何交叉JS構造函數的兩個任務 - 特權方法和構造函數邏輯的定義 - 按正確的順序調用?

附錄 - 附加材料,由於意見

我從評論想通了,它似乎並沒有被清楚我想要什麼。因此,這裏是用Java編寫的

class Parent { 
    public Parent() { 
    methodA(); 
    } 

    public void methodA() { 
    System.out.println("I do the work of the parent's method"); 
    } 
} 

class Child extends Parent { 
    public Child { 
    super(); 
    } 

    public void methodA() { 
    System.out.println("I do the work of the child's method and ..."); 
    super(); 
    } 
} 

Parent p = new Parent(); 
Child c = new Child(); 

的例子這將導致下面的輸出

$> I do the work of the parent's method 
$> I do the work of the child's method and ... 
$> I do the work of the parent's method 

這是什麼情況。 Parent的構造函數調用Parent中定義的methodA的實現。這沒什麼特別的,併產生第一行輸出。 Child的構造函數只是調用父類的構造函數,它再次像以前那樣調用methodA。但是,儘管這是父級的構造函數,但該對象仍然是Child的一個實例,因此將執行子級的methodA的實現。此方法打印輸出的第二行,然後顯式調用生成第三行的父級方法。

根據OOP,這是完美的正確行爲,這也是我想用Javascript實現的。所以它實際上是opposite of the problem mentioned here。鏈接來自評論。

+0

哪裏是'methodB'? – Ben

+0

您的問題不是基於原型的繼承或特權方法,而是從構造函數中調用可覆蓋的方法。這在我見過的任何語言中都不太好。 – Bergi

+0

@BenAston:對不起,'methodB'是評論中的一個錯字。該示例的以前版本使用了兩種方法,但我將MWE簡化爲一種方法。 – user2690527

回答

-1

真的不知道你怎麼想在這裏實現,但總體來講,你可以做這樣的事情:

function Parent() { 
    if (this.methodA == null) { 
    this.methodA = function() { 
     // do something 
     console.log('parent'); 
    }; 
    } 

    // C'tor logic starts here 
    // Beside other things also call some method of this object 
    this.methodA(); 
} 

function Child() { 

    this.methodA = (function(_oldMethodA) { 
    return function() { 
     console.log('child'); 
     // do something special and then call parent method 
     if (_oldMethodA) { 
     _oldMethodA.call(this); 
     } 
    } 
    })(this.methodA); 

    Parent.call(this); 
} 

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

new Child(); // yields: 'child' 

但判斷上,你想做的事,你可能要添加一些數組中的父母,發生了什麼是你在父類中重寫你的方法A

+0

在你的'孩子'中,'_oldMethodA'總是'未定義' – Bergi

+0

不,這個「解決方案」沒有任何意義。正如Bergi所說,'_oldMethodA'總是未定義的,因爲它是一個未命名函數的參數,它以'this.methodA'作爲參數被調用,但'this.methodA'仍有待定義。此代碼顯示某種「自我指涉」。 – user2690527

0

在調用父類之前,可以將該屬性定義爲子類中的一個訪問器。

這樣,您將能夠獲得對父類指定的函數的引用,但仍可在getter中提供所需的函數。

function Parent() { 
 
    this.methodA = function() { console.log('Parent method'); }; 
 
    this.methodA(); 
 
} 
 
function Child() { 
 
    var _oldMethodA; 
 
    var _newMethodA = function() { 
 
    console.log('Code injected by Child'); 
 
    _oldMethodA.call(this); 
 
    }; 
 
    Object.defineProperty(this, 'methodA', { 
 
    configurable: true, 
 
    enumerable: true, 
 
    set: function(val){ _oldMethodA = val; }, 
 
    get: function(){ return _newMethodA; } 
 
    }); 
 
    Parent.call(this); 
 
    /* Optional: convert it back to a data property */ 
 
    Object.defineProperty(this, 'methodA', { 
 
    value: _newMethodA, 
 
    writable: true 
 
    }); 
 
} 
 
Child.prototype = Object.create(Parent.prototype); 
 
Child.prototype.constructor = Child; 
 
new Child();

+0

Urgh。我很高興這不再在ES6中工作:-) – Bergi

+0

@Bergi是的,這是醜陋的代碼。但我認爲它應該仍然在ES6中工作,不是嗎? – Oriol

+0

它似乎在做我想達到的目標,我尊重想到這個解決方案所需的創造力。但它太複雜了,我不想使用它。對不起;-)代碼必須清晰準確。這實際上看起來像有人試圖手動執行代碼混淆;-) – user2690527