2016-06-25 9 views
1

ECMAScript 2015のnew.targetプロパティについて読んでいました。私はそれが面白いと思った、私は新しい演算子を使用して関数を設定し、通常の呼び出しでそれを呼び出すことができます。しかし何らかの理由で、これはうまくいかないようです。これは私のテストコードです。バインドされた関数でnew.targetプロパティが予期しない動作をする

function Test(newConfig) { 
    if(new.target){ 
    if(Test2 !== undefined){ 
     console.log(new.target === Test2);// why does this give false 
     console.log(new.target === Test);// why does this give true 
    } 
    let mergedConfig = {}; 
    Object.assign(mergedConfig, newConfig || {}, new.target.config || {}) 
    let fn = Test.bind({config: mergedConfig}); 
    fn.config = mergedConfig; 
    return fn; 
    } else { 
    // do something with this.config 
    return this.config.a + this.config.b; 
    } 
} 

// initial configuration 
// the first time I'm calling the Test function, so new.target === Test 
var Test2 = new Test({ 
    a: 'a' 
}); 
// further configuration 
// the second time I'm calling the Test2 function. 
// Now, new.target !== Test2, but new.target === Test. 
// This is what seems weird to me. 
let Test3 = new Test2({b: 'b'}); 

// normal call 
// new.target === undefined 
let result = Test3(); 
+0

私はあなたが読んでいたもの、またはあなたが* new演算子を使用して機能を設定し、その後でそれを呼び出す」によって何を意味するかわからないが通常の呼び出し* "となりますが、' this'キーワードと混同しているようです。最初に 'Test2'を取得した理由を説明してください。 – Bergi

+0

'ReferenceError: '初期化の前にTest2'という字句宣言にアクセスできません。 'Test2'を' var'で宣言したのですか? 'if(Test2!== undefined)'は、 'Test2'が初期化されたか、TDZにあるかどうかを確かめる方法ではありません。 – Oriol

+0

あなたはそうです。 varにする必要があります。問題をより明確にするために、コードを実際のテストコードから少し変更し、ECMAScript 6のようにしました。 – raichu

答えて

2

new.targetは必ずしも呼び出される関数を参照するとは限りません。むしろ、新しいインスタンスのプロトタイプとして.prototypeプロパティを使用する関数を指します(スーパークラスが正しいものを作成できるように)。

.bind()メソッドは、指定されたthis値と部分的に適用された引数リストを使用して元の関数を呼び出すことのみを目的とする特殊な "結合関数"オブジェクトを作成します。彼らは.prototypeプロパティを持っていない - それはnew.targetの適切な値ではないことを明確にする必要があります。実際には、それらの[[construct]] methodは、バインドされた関数の代わりに元の関数を使用するように指定されています。


ここで何をすべきですか?もちろん、機能を設定するのに "newを使用する"は、プロダクションコードでは避けるべきですが、素晴らしい実験です。私はここbindを避けるために提案し、代わりにクロージャの使用するだろう:

function makeTest(config) { 
    return function ConfiguredTest(newConfig) { 
     if (new.target) { 
      let mergedConfig = {}; 
      Object.assign(mergedConfig, newConfig || {}, config) // I presume you want to swap the latter two 
      return makeTest(mergedConfig); 
     } else { 
      // use `config` here 
      return config.a + config.b; 
     } 
    }; 
} 
const Test = makeTest({}); 

// like before 
let Test2 = new Test(…) 
let Test3 = new Test2(…) 
Test3() 
+0

あなたの徹底的な対応が気に入っています。ありがとう。 – raichu

関連する問題