2017-10-16 124 views
3

請考慮這樣的代碼:的JavaScript - 原型鏈

class a { 
    constructor() { 
     this.test = "test from a"; 
     this.testA = "X"; 
    } 

    mimi() { 
     console.log('aaaaaaaa', this.test, this.testA) 
    } 

} 

class b extends a { 
    constructor() { 
     super(); 
     this.test = "test from b" 
    } 

    mimi() { 
     console.log('bbbbbbbb', this.test, this.testA) 
    } 

} 

class c extends b { 
    constructor() { 
     super(); 
     this.test = "test from c" 
    } 

    mimi() { 
     console.log('cccccccc', this.test, this.testA) 
    } 

    meme() { 
     var test = kalreg.__proto__.__proto__; 
     test.mimi(); 
     var test2 = kalreg.__proto__.__proto__.__proto__; 
     test2.mimi(); 
    } 
} 

var kalreg = new c(); kalreg.mimi(); kalreg.meme(); 

我得到的輸出是:

cccccccc test from c X 
bbbbbbbb undefined undefined 
aaaaaaaa undefined undefined 

我的目標邏輯讓我用「一個」爲最通用類,作爲小孩的「b」,作爲「b」的小孩的「c」。我想「Ç」擁有的「b」和「a」而是功能的一部分「一個」被覆蓋「b」所以唯一的辦法「Ç」所有方法和屬性可能有權訪問覆蓋的功能是使用原型鏈。 不幸的是,我的路行不通,因此問題是:

  1. meme()功能,如何避免kalreg.proto - 我已經告訴訪問原型的這樣的方式是邪惡和危險的代碼。
  2. 在我看來,輸出中應該沒有「未定義」,但是,有。 預期的輸出結果是:從B X從X

如何實現從C X

CCCCCCCC測試

BBBBBBBB測試

AAAAAAAA測試?

謝謝!

回答

3

in meme() function,如何避免kalreg。

使用super的使用情況下,你確實需要訪問從超類的屬性(但要注意,不會與testtestA幫助,因爲這些都不是在超或它的prototype對象,它們使用new c創建的實例;更多內容在下面)。

另外:避免__proto__。在需要訪問對象原型的罕見情況下,請使用Object.getPrototypeOf

在我看來,應該沒有「未定義」的輸出,但是有。預期輸出是:從B X選自C X

CCCCCCCC測試

BBBBBBBB測試從X

的輸出是正確

AAAAAAAA測試,因爲原型對象在其上」重新撥打mimi沒有testtestA屬性。只有使用new c創建的對象才具有這些屬性。而且只有一個這樣的對象,所以test將會是"test from c",不管你撥打哪個mimi,而testA永遠是"X"

在一個評論中,你已經問過當每個構造函數在其中有this.test = ...時只有一個test。讓我們來看看什麼是在內存中,一旦你做了var kalreg = new c();

 
             +−−−−−−−−−−−−+ 
a−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| (function) | +−−−>(Function.prototype) 
             | +−−−−−−−−−−−−+ | 
             | | __proto__ |−−+   +−−−−−−−−−−−−−+ 
             | | prototype |−−−−−−−−−−+−>| (object) | 
             | +−−−−−−−−−−−−+   | +−−−−−−−−−−−−−+ 
             |       | | __proto__ |−−>... 
         +−−−−−−−−−−−−+ |       | | constructor |−−>a 
b−−−−−−−−−−−−−−−−−−−+−>| (function) | |       | | mimi  |−−>... 
        | +−−−−−−−−−−−−+ |       | +−−−−−−−−−−−−−+ 
        | | __proto__ |−+   +−−−−−−−−−−−−−+ | 
        | | prototype |−−−−−−−−+−>| (object) | | 
        | +−−−−−−−−−−−−+  | +−−−−−−−−−−−−−+ | 
        |      | | __proto__ |−−+ 
    +−−−−−−−−−−−−+ |      | | constructor |−−>b 
c−−−>| (function) | |      | | mimi  |−−>... 
    +−−−−−−−−−−−−+ |      | +−−−−−−−−−−−−−+ 
    | __proto__ |−+  +−−−−−−−−−−−−−+ | 
    | prototype |−−−−−−−+−>| (object) | | 
    +−−−−−−−−−−−−+  | +−−−−−−−−−−−−−+ | 
          | | __proto__ |−+ 
          | | constructor |−−>c 
      +−−−−−−−−−−−−+ | | mimi  |−−>... 
kalreg−−−>| (object) | | | meme  |−−>... 
      +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ 
      | __proto__ |−−+ 
      | test  | 
      | testA  | 
      +−−−−−−−−−−−−+ 

正如你所看到的,只有對象kalreg點到了testtestA。爲什麼?因爲在調用每個構造函數期間,this引用該對象;這就是newsuper()的工作方式。因此,由於this引用了該對象,因此每個構造函數都會執行其this.test = ...一行,並且由於c中的那個是最後一個運行的對象,因此它「獲勝」。

您可以訪問mimi方法的超類版本,但由於它們全都顯示test屬性,它們都將顯示"test from c"。要顯示不同的東西,他們必須要有不同的屬性才能顯示。此外,與super你只能去一個級別,所以如果你想要去向上兩級,你要麼使用a.prototype.mimi(或this.__proto__.__proto__.mimi明確,或把一些設施在b調用amimi

具有用於每個級別不同的屬性,並與b提供superMimi實施例這樣c可以使用amimi

class a { 
 
    constructor() { 
 
     this.testA = "test from a (this.testA)"; 
 
    } 
 

 
    mimi() { 
 
     console.log('aaaaaaaa', this.testA); 
 
    } 
 
} 
 

 
class b extends a { 
 
    constructor() { 
 
     super(); 
 
     this.testB = "test from b (this.testB)"; 
 
    } 
 

 
    mimi() { 
 
     console.log('bbbbbbbb', this.testB) 
 
    } 
 
    
 
    superMimi() { 
 
     return super.mimi(); 
 
    } 
 
} 
 

 
class c extends b { 
 
    constructor() { 
 
     super(); 
 
     this.testC = "test from c (this.testC)"; 
 
    } 
 

 
    mimi() { 
 
     console.log('cccccccc', this.testC); 
 
    } 
 

 
    meme() { 
 
     super.mimi();  // Uses b's version 
 
     super.superMimi(); // Uses a's version 
 
     this.__proto__.__proto__.__proto__.mimi.call(this); // Also uses a's version 
 
     var p = Object.getPrototypeOf(this); 
 
     var p2 = Object.getPrototypeOf(p); 
 
     var p3 = Object.getPrototypeOf(p2); 
 
     p3.mimi.call(this); // Also uses a's version 
 
    } 
 
} 
 

 
var kalreg = new c(); 
 
kalreg.mimi(); 
 
kalreg.meme();

+0

對象如何可能沒有this.test每個類是否在它們的構造函數中定義了this.test? – Kalreg

+0

您可否詳細說明如何在'meme()'方法中使用'super'來完成OPs的目標。 – Adam

+1

@亞當:完成,感謝您將它掛起,我的意思是回到那個並忘記。 :-) –