new.target属性在绑定函数中表现出意外

时间:2016-06-25 22:26:52

标签: javascript ecmascript-6

我正在阅读ECMAScript 2015 new.target属性。我觉得这很有意思,我可以使用new运算符配置一个函数,然后通过普通调用来调用它。但由于某种原因,这似乎不起作用。这是我的测试代码。

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();

1 个答案:

答案 0 :(得分: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()