如何在不同的上下文中使用es6构造函数指令

时间:2019-02-11 00:10:13

标签: javascript ecmascript-6 constructor ecmascript-5

是否可以通过更改“ this”上下文(调用,应用或其他)在另一个实例上使用es6构造函数指令?使用es5“类”可以做到这一点。这是我的意思的一个小例子:

function ES5() {
  this.foo = 'foo';
}

class ES6 {
  constructor() {
    this.bar = 'bar';
  }
}

var a = new ES6();
ES5.call(a);
console.log(a.foo + a.bar); //foobar



var b = new ES5();
//Reflect.construct(ES6); ??
ES6.call(b); //TypeError: Class constructor ES6 cannot be invoked without 'new'

console.log(b.foo + b.bar); //how to get foobar here too?

编辑: 我的问题与新关键字无关。我正在寻找的答案是如何使用另一个“此”上下文(带有或不带有new关键字)运行es6构造函数中放置的指令。

1 个答案:

答案 0 :(得分:4)

正如评论和您自己所指出的那样,如果有任何解决方法,尝试使用自定义this上下文调用类构造函数确实不是您想要尝试的事情。这是故意使然!

如果出于某些原因这不可避免地无法证明棘手的解决方法合理,则可以在下面找到两个部分解决方案。它们都以自己的方式是不完美的-根据您的实际情况,其中之一可能仍然适合您的需求。


解决方法1

虽然无法在构造函数调用中直接设置this,但可以将this的原型设置为您选择的对象

为此,您可以使用Reflect.construct()来调用带有自定义[[Construct]]值的内部new.target方法。然后this将初始化为从new.target.prototype继承的对象。

以您的示例为基础:

function ES5() {
    this.foo = 'foo';
}

class ES6 {
    constructor() {
        this.bar = 'bar';
    }
}

let b = new ES5();

function TemporaryHelperConstructor() {}
TemporaryHelperConstructor.prototype = b;

b = Reflect.construct( ES6, [], TemporaryHelperConstructor ); // The third argument corresponds to the value of new.target

console.log( b.foo + b.bar ); // foobar !

(规范的26.1.29.2.2部分介绍了Reflect.construct()和内部[[Construct]]方法的确切工作原理

潜在问题

  • 实际上未使用绑定到this的{​​{1}}来调用类构造函数,而是使用绑定到直接继承自b的空对象的this来调用类构造函数。如果您或类构造函数依赖于bObject.getOwnPropertyNames()等方法,则可能会导致问题。

解决方法2

虽然不可能在不引起Object.getPrototypeOf()的情况下调用类构造函数的内部[[Call]]方法,但可以提取附加到类构造函数的代码块并创建一个普通的函数,然后您可以使用自定义TypeError绑定进行调用。

您可以使用this方法将类构造函数的代码块提取为字符串。然后,Function.prototype.toString()构造函数可以从此字符串中构造一个普通函数,您可以通过自定义Function()通过this进行绑定来调用该函数。

以您的示例为基础:

Function.prototype.apply()

请注意,此代码段使用极为简化的正则表达式进行演示。为了使事情变得健壮,您需要考虑嵌套的花括号和字符串和注释中的花括号。如果需要,还需要提取构造函数参数。

(根据规范的19.2.3.5部分,您可以依靠function ES5() { this.foo = 'foo'; } class ES6 { constructor() { this.bar = 'bar'; } } const b = new ES5(); const constructorBody = ES6.toString().match( /(?<=constructor\(\) ){[^}]*}/ )[0] const ordinaryFunction = Function( constructorBody ) ordinaryFunction.apply( b ); // No TypeError console.log( b.foo + b.bar ); // foobar !的足够一致的输出来使这种方法在各种实现中都可以使用。)

潜在问题

  • Function.prototype.toString()在执行普通函数时将设置为new.target(与undefined调用一样),如果类构造函数正在使用它,可能会引起问题。 / li>
  • 使用[[Call]]MDN)创建的新函数将失去对原始类构造函数的关闭,如果类构造函数依赖于它们,则可能导致Function()
  • li>
  • 如果使用ReferenceErrors应用于派生类,则此方法将导致SyntaxError,这在普通函数中不是有效的语法。

结论

没有完美的解决方案来解决您的问题。如果您的用例足够简单,那么您仍然可以实现所需的功能。部分解决方法将带有其自身的有害问题-谨慎行事!