2016-08-22 6 views
3

私はこの動作を理解しようとしています。私はES6クラスで観察しています。次のコードを考えてみましょう。とてもシンプルです:親クラス(Parent)と子クラス(Child)を継承しています。 Parentクラスには、getLabelというメソッドがあり、これは単にそのクラスのlabelプロパティを返します。ES6でObject.assignの動作を理解しようとしています

子クラスのインスタンスを作成するときに、そのラベルを設定して、それをすべてうまく印刷しようとします。

ただし、最初のインスタンスでを使用して子クラスの別のインスタンスを作成すると、明示的に変更していても、新しいインスタンスは1番目のインスタンスのラベル値を保持します。

class Parent { 
    constructor(label) { 
    this.getLabel =() => { 
     return this.label; 
    }; 
    this.label = label; 
    } 
} 

class Child extends Parent { 
    constructor(label) { 
    super(label); 
    this.label = label; 
    } 
} 

const c = new Child('Child'); 
console.log('c getLabel() = ' + c.getLabel());//Prints "Child" 
const c1 = Object.assign(new Child('C1'), c); 
c1.label = 'Child Modified'; 
console.log('c1 getLabel() = ' + c1.getLabel());//Prints "Child" again instead of "Child Modified". 

なぜこれが起こっているのかわかりません!私はその後、Parentクラスで私はgetLabelメソッドを定義しています方法を変更されたのは何

:誰かがこれらの二つの異なる動作を説明できる場合

class Parent2 { 
    constructor(label) { 
    this.label = label; 
    } 

    getLabel() { 
    return this.label; 
    } 
} 

class Child2 extends Parent2 { 
    constructor(label) { 
    super(label); 
    this.label = label; 
    } 
} 

const c2 = new Child2('Child 2'); 
console.log('c2 getLabel() = ' + c2.getLabel());//Prints "Child 2" as expected. 
const c3 = Object.assign(new Child2('C3'), c2); 
c3.label = 'Child 2 Modified'; 
console.log('c3 getLabel() = ' + c3.getLabel());//Prints "Child 2 Modified" as expected. 

は、私には理解されます。

上記のコードでは、ES6フィドルはhttp://www.es6fiddle.net/is6ex359/です。

+1

矢印関数は字句「this」を使用します。あなたのオブジェクトには、 'Object.assign'を呼び出すときに新しい子にコピーされる' getLabel'というプロパティがあります。そのプロパティには元のParentへのレキシカル 'this'リファレンスを持つ関数が含まれています。矢印関数の代わりに通常の関数を使用した場合、その動作は表示されません。 – Paulpro

+1

ところで、 'super(label)'は既に 'this.label'を割り当てているので、' this.label = label'は必要ありません。 – Oriol

+0

@Oriol ...ありがとう!この質問の例を考え出すのは私だけでした。 –

答えて

7

getLabelはそれぞれのインスタンスで定義されているため、プロトタイプでは共有されていません。また、矢印関数を使用して定義するため、thisのローカルバインディングは定義されていません。thisの値はconstructorの1つになります。あなたがObject.assignを使用する場合

その後、あなたはc1にそれを呼び出す場合でも、c1cの方法を受け取り、this値がcになります。だからc.labelが得られますが、これはまだ'Child'です。

矢印機能は使用しないでください。

class Parent { 
 
    constructor(label) { 
 
    this.label = label; 
 
    } 
 
    getLabel() { 
 
    return this.label; 
 
    } 
 
} 
 
class Child extends Parent { 
 
    constructor(label) { 
 
    super(label); 
 
    this.label = label; 
 
    } 
 
} 
 
const c = new Child('Child'); 
 
console.log('c getLabel() = ' + c.getLabel()); // "Child" 
 
const c1 = Object.assign(new Child('C1'), c); 
 
c1.label = 'Child Modified'; 
 
console.log('c1 getLabel() = ' + c1.getLabel()); // "Child Modified"

(注Object.assignはとにかくそれが継承されているためgetLabelを割り当てるが、c1.getLabel ==== c.getLabelしません)

またはコンストラクタではなく、機能を使用して:私は、プロトタイプのメソッドを定義するお勧めします式:

class Parent { 
 
    constructor(label) { 
 
    this.getLabel = function() { 
 
     return this.label; 
 
    }; 
 
    this.label = label; 
 
    } 
 
} 
 
class Child extends Parent { 
 
    constructor(label) { 
 
    super(label); 
 
    this.label = label; 
 
    } 
 
} 
 
const c = new Child('Child'); 
 
console.log('c getLabel() = ' + c.getLabel()); // "Child" 
 
const c1 = Object.assign(new Child('C1'), c); 
 
c1.label = 'Child Modified'; 
 
console.log('c1 getLabel() = ' + c1.getLabel()); // "Child Modified"

+3

これは、問題が矢印機能の使用によるものであった今日の2番目の質問です。私は人々が単純な構文に恋しているのではないかと思います。そして、それはこの振る舞いに大きな違いがあることを認識していません。 – Barmar

+0

コールバック関数には適していますが、オブジェクトメソッドには適していません。 – Barmar

+1

@Barmar:そのため、http://stackoverflow.com/q/34361379/218196を作成しましたが、まだ具体的です(このユースケースは個人的には適合しません)。個人的には、矢印の誤用が1つの質問の重複として機能するすべての質問を閉じることができればと思っていますが、これはたぶん希望の考えです。 –