3

I'm running babelify 7.2.0 with Gulp and I'm getting an error on the following code:

class One {}

class Two extends One {
  constructor() {
    this.name = 'John';
  }
}

Here is the crux of the error:

SyntaxError: [the file path in question]: 'this' is not allowed before super()
  20 | class Two extends One {
  21 |   constructor() {
> 22 |     this.name = 'John';
     |     ^
  23 |   }
  24 | }
  25 | 

It seems to me that this should not be firing because I am not making any super calls within the constructor at all so there's no risk of conflict. I've submitted an issue already on Github but I'm wondering if there's a way I can turn it off in the mean time.

rescuecreative
  • 3,097
  • 2
  • 14
  • 25

3 Answers3

6

This isn't a bug. Subclasses must call super explicitly before attempting to access this:

class Two extends One {
    constructor(...args) {
        super(...args);
        this.name = 'John';
    }
}

This is defined in ECMAScript standard (see this answer), and Babel follows it closely.

Community
  • 1
  • 1
vaultah
  • 36,713
  • 12
  • 105
  • 132
  • After seeing this answer I did some more reading and it seems that you may be correct. If so that makes me very sad. There is literally no problem whatsoever that you can cause by referencing `this` if you don't reference `super` at all. I read one article that said without calling `super`, JavaScript doesn't know what `this` is. To be honest, if that's true, it's poor design. I think a lot of us could write a system that didn't require a `super` call on a child class constructor pretty easily. – rescuecreative Dec 09 '15 at 07:14
  • 1
    @rescuecreative: *"There is literally no problem whatsoever that you can cause by referencing this if you don't reference super at all."* There is. The reason why that is enforced is that if the class extends a built-in class, such as `Array` or `Error`, `this` most be initialized properly before any access to it happens. – Felix Kling Dec 09 '15 at 09:00
  • @FelixKling I just spent a good while thinking hard about how I could prove you wrong, but I can't. You are correct. To be fair, I think you don't necessarily HAVE to couple constructors so tightly to the basic nature of what an object is, for example whether it's an ordered or an unordered collection. There are certain things that could be implicitly derived just via the extension that _might_ remove the need to make a `super` call. But it would take me more time to experiment with that than I have right now :) – rescuecreative Dec 10 '15 at 15:46
0

No, there's no way to "turn this off" as this is a requirement defined in the ECMAScript 2015 standard.

this is not available prior to super(...) call in the constructor of an extending class.

The exact details of where in the standard this is defined can be seen in this answer.

Community
  • 1
  • 1
Amit
  • 41,690
  • 8
  • 66
  • 101
0

This isn't a Babel thing, it's defined in ES2015. You can't turn it off.

In a derived constructor, this is undefined prior to calling super. Unlike (say) Java, calls to super are never implicit, you must write them explicitly.

This is defined primarily in §9.2.2, [[Construct]] ( argumentsList, newTarget), and §12.3.5.1, the runtime semantics for super: [[Construct]] only calls OrdinaryCallBindThis if the [[ConstructorKind]] is "base" (not "derived"). Otherwise, this remains undefined until you call super, part of which calls [[Construct]] on the super constructor, which either calls its own super (if it is also a derived constructor) or OrdinaryCallBindThis (if it's a base constructor).

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639