Reputation: 605
Javascript's super
keyword, when I run the code on Chrome, Babel, TypeScript, I got different results.
My question is which result is correct? And what part of specification defines such behavior?
The following code:
class Point {
getX() {
console.log(this.x); // C
}
}
class ColorPoint extends Point {
constructor() {
super();
this.x = 2;
super.x = 3;
console.log(this.x) // A
console.log(super.x) // B
}
m() {
this.getX()
}
}
const cp = new ColorPoint();
cp.m();
The results:
links:
Upvotes: 9
Views: 1555
Reputation: 6315
Chrome is correct. And this is caused by the unbalance between get and set.
OrdinarySet is reciever
sensitive, but OrdinaryGet is not.
So super.x = 3
has the same effect of this.x = 3
, because the receiver here is this
. Evaluatingsuper.x
, which never reach this
, will always get undefined
because A.prototype
does not have such field.
The super.x
is a SuperReference. And assignment to SuperReference
will call PutValue(V, W), which in turn call super
object's internal slot [[Set]] and finally OrdinarySet
.
In plain JavaScript, the statement super.x = 3
is basically equivalent to:
OrdinarySet(proto, 'x', 3, this)
.
Where proto
is the super object, internally the [[HomeObject]]
of constructor ColorPoint
. proto
is equivalent to Object.create(Point.prototype)
, as the ClassDefinitionEvaluation specifies, and it is passed to constructor as [[HomeObject]]
.
Now let's see how OrdinarySet
works. In step 4c and 4d, the spec requires set operation is done on receiver this
, not the proto
object.
Let existingDescriptor be ? Receiver.[GetOwnProperty].
If existingDescriptor is not undefined, then
If IsAccessorDescriptor(existingDescriptor) is true, return false.
If existingDescriptor.[[Writable]] is false, return false.
Let valueDesc be the PropertyDescriptor{[[Value]]: V}.
Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
These statements says OrdinarySet(proto, 3, this)
means this.x = 3
.
On the other hand, OrdinaryGet
ignores Receiver
. super.x
is
OrdinaryGet(proto, 'x', this)
.
OrdinaryGet
does not have Receiver
in its clauses at all! So super.x
is equivalent to Object.create(Point.prototype).x
, which is undefined
of course.
As a rule of thumb, if there is discrepancy between transpilers and browsers, browsers, especially Chrome, are usually more loyal to the ECMAScript specification. Transpilers usually trade some edge case correctness for runtime efficiency.
Upvotes: 7
Reputation: 901
Diffrence I saw :-
super
helps to take all the this part of above class in it
and we can change that this accordingly`
we can change this.x of class point by super.x OR this.x in JAVASCRIPT But we can can't make change in tyescript with super.x (it will behave the new obect of class colorPoint)..this change can only be happen by this.x
we can't make even call 2nd time to super() in JAVASCRIPT it will give an err and we can call the super() in type script it will make re-Initilize the Point constructor class
Typescript thing I have notice in TypeScript Playground by Runing it
"use strict";
class Point {
getX() {
console.log("POINT " + this.x);
}
constructor() {
this.x = 10;
}
}
class ColorPoint extends Point {
constructor() {
super();
this.y = 2;
console.log("THIS x" + this.x); // 10
console.log("THIS y" + this.y); // 2
console.log("SUPER !" + super.x); // undef
super.x = 3;
console.log("THIS.x after a " + this.x); // 10
this.x = 20;
console.log("THIS.x after b " + this.x); // 20
super();
console.log("SUPER x" + super.x); //
console.log("THIS x" + this.x); //
console.log(this); // give this of colorPoint
console.log(super()); // give this of colorPoint
}
}
const cp = new ColorPoint();
cp.getX();
Javascript thing i have notice in console by command node super.js
"use strict";
class Point {
getX() {
console.log("POINT " + this.x);
}
constructor() {
this.x = 10;
}
}
class ColorPoint extends Point {
constructor() {
super();
this.y = 2;
console.log("THIS x" + this.x); //
console.log("THIS y" + this.y); //
// console.log("SUPER" + super.x); //
super.x = 3;
console.log("THIS.x after a " + this.x); //
this.x = 20;
console.log("THIS.x after b " + this.x); //
//gives err
// super();
// console.log("SUPER x" + super.x); //
// console.log("THIS x" + this.x); //
}
// m() {
// this.getX();
// }
}
const cp = new ColorPoint();
cp.getX();
Upvotes: 0
Reputation: 275867
A rule of programming Garbage in -> Garbage out
. The following code :
class Point {
x: number;
getX() {
console.log(this.x);
}
}
class ColorPoint extends Point {
constructor() {
super();
this.x = 2;
super.x = 3; // ERROR
}
}
You get a nice TypeScript error Only public and protected methods can be accessed
. Note the word methods
. super
should not be used for properties
. Invalid code is not something you should run.
Upvotes: -1