Description
In classes that extend ES5 constructor functions, the value returned by a call to super()
within the constructor does not match the value of this
.
function A() {}
class B extends A {
constructor() {
const _super = super();
if (_super !== this) {
throw new Error(`Expected ${_super} to equal this`);
}
}
}
new B(); // throws Error: Expected undefined to equal this
It seems that the return value of the base constructor function is used as the return value of super()
, unless the constructor function returns an object.
function A() { return 'test'; }
// class B as above
new B(): // throws Error: Expected test to equal this
function A() { return { test: true }; }
// class B as above
new B(): // does not throw
class A { constructor() { return 'test'; }}
// class B as above
new B(): // also does not throw when A is a class instead of ES5 constructor function
Chrome, Firefox, and Safari do not throw in any of these cases.
I found this because code similar to this is generated by Babel when transforming async arrow function properties that reference this
. The async function transform uses a generator function, and since generator arrow functions aren't yet available, the generator function closes over the return value of super()
for use in place of this
in the former arrow function. React.Component
is distributed as an ES5 constructor function, so my React components that use async arrow function properties all produce this problem code -- React.Component
has no return statement, so in my case super()
returns undefined
.
Here's some example code that causes Babel to produce the problem code: https://babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=GYVwdgxgLglg9mABAYTgWwA4IKZigCgEoBvAXwChyIAbAQwGd7EB1GAEwHNspFsAPKLjZNUmHHkTFyiRAEg-iALyIA5AAts1anBUBuaTMRs4AZXTc1MMByWIGAT0iIiSgHySDhwxAT041bAA6bQ58KEt6QL5CT0QKCnIwbAB3FnYuAkJA4zM0CytQwl0gA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&lineWrap=false&presets=es2017%2Cstage-2&prettier=false&targets=&version=6.26.0&envVersion=
Interestingly, the TypeScript compiler seems to avoid the problem (at least when the constructor function returns undefined
) by using super() || this
to capture the value used in closures. This was apparently added along with a change to support override values returned by base class constructors in this PR.
Tested in Edge 15 and 16. Apologies if this doesn't repro on ChakraCore's master, or if this is the wrong place to report.