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

问题描述 投票:6回答:1

是否可以通过更改“this”上下文(call,apply或其他)来在另一个实例上使用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?

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

javascript ecmascript-6 constructor ecmascript-5
1个回答
4
投票

正如评论和你自己所指出的那样,尝试使用自定义this上下文调用类构造函数实际上并不是你想要尝试的东西,如果它有任何解决方法。这故意变得很难!

如果由于某些原因,这是不可避免的,足以证明棘手的解决方法,你可以在下面找到两个部分解决方案。它们各自都不完美 - 根据您的具体情况,其中一个可能仍然符合您的需求。


Workaround 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 !

Reflect.construct()和内部[[Construct]]方法的确切工作在规格的26.1.29.2.2部分中描述)

潜在问题

  • 实际上没有使用绑定到thisb调用类构造函数,使用绑定到直接继承自this的空对象的b调用它。如果您或类构造函数依赖于Object.getOwnPropertyNames()Object.getPrototypeOf()等方法,这可能会导致问题。

Workaround 2

虽然不能在不导致[[Call]]的情况下调用类构造函数的内部TypeError方法,但是可以提取附加到类构造函数的代码块并从中创建一个普通函数,然后可以使用自定义this调用它。捆绑。

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

以您的示例为基础:

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 !

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

(根据规范的19.2.3.5部分,你可以依靠Function.prototype.toString()的足够一致的输出来实现这种方法。)

潜在问题

  • 执行普通函数时,new.target将被设置为undefined(如[[Call]]调用的情况一样),如果类构造函数使用它,可能会导致问题。
  • 使用Function()MDN)创建的新函数将丢失原始类构造函数的闭包,如果类构造函数依赖它们,则可能导致ReferenceErrors
  • 如果使用SyntaxError在派生类上应用这种方法将导致super(),这在普通函数中不是有效的语法。

Conclusion

你的问题没有完美的解决方案。如果你的用例很简单,你仍然可以达到你想要的效果。部分解决方法将伴随着他们自己的有害问题 - 谨慎行事!

© www.soinside.com 2019 - 2024. All rights reserved.