HI Jordan,
Great questions.
At first I thought the approach/syntax could be:
class Rectangle {
constructor(this.height, this.width) {}
}
// equivalent to:
class Rectangle { constructor() {
[this.height, this.width] = arguments;
}}
Which would not create the height
or width
bindings. But, as I think you're alluding to, this becomes problematic with derived classes.
class Shape {
constructor(this.area) {}
}
class Rectangle extends Shape {
constructor(this.height, this.width) {
super(this.height * this.width);
// ReferenceError: Must call super constructor in derived class before accessing 'this'
}
}
So this seems to suggest that the syntax does need to make the parameter available directly on the constructor scope first so it can be used with the super constructor, and only after the super constructor would the value be assigned to the instance property.
On reflection the this <identifier>
syntax does seem ambiguous if someone would expect that reassigning the identifier to also assign to the property. As you say, assigning to both does seem magical and only matches the behaviour of function parameters and the arguments
object in sloppy-mode. So it seems best for the two to not influence each other (this is how TypeScript also implements this feature). It would be interesting to study if this behaviour could increase the chance of bugs for those that assume different behaviour and receive no error message.
Potentially to disambiguate between the scope binding and the property assignment the syntax could be split as in the following example, where the scope binding is declared separately and opt-in. Inspired by https://github.com/zkat/proposal-as-patterns
class Rectangle extends Shape {
constructor(this.height as height, this.width as width) {
super(height * width);
}
}
Of course this is closer in verbosity to existing code. Only cutting the repetition of 'height' down from 4 to 3.
class Rectangle extends Shape {
constructor(height, width) {
super(height * width);
this.height = height;
this.width = width;
}
}
Which makes me prefer the original keyword syntax this height, this width
. Which cuts the repetition of 'height' down from 4 to 2, providing (in my opinion) a greater net benefit.
class Rectangle extends Shape {
constructor(this height, this width) {
super(height * width);
}
}