ES6继承:使用`super`来访问父类的属性

jus*_*vac 8 javascript inheritance babel typescript ecmascript-6

Javascript的super关键字,当我在Chrome,Babel,TypeScript上运行代码时,我得到了不同的结果.

我的问题是哪个结果是正确的?规范的哪一部分定义了这种行为?

以下代码:

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();
Run Code Online (Sandbox Code Playgroud)

结果:

  • Chrome 58.0.3029.110 64bit(V8 5.8.283.38)
  • Babel Repl 6.24.2
  • TypeScript 2.3

链接:

Her*_*lme 5

简短回答:

Chrome是正确的.这是由get和set之间的不平衡引起的.

OrdinarySetreciever敏感的,但普通的Get不是.

所以super.x = 3具有相同的效果this.x = 3,因为这里的接收器是this.super.x从未达到过的评估this总会得到,undefined因为A.prototype没有这样的领域.


更多细节:

super.x是一个SuperReference.并且赋值SuperReference将调用PutValue(V,W),然后调用super对象的内部插槽[[Set]],最后调用OrdinarySet.

在纯JavaScript中,该语句super.x = 3基本上等同于:

OrdinarySet(proto, 'x', 3, this).

proto超级对象在哪里,在[[HomeObject]]构造函数内部ColorPoint.proto相当于Object.create(Point.prototype)作为ClassDefinitionEvaluation指定,并且它被传递给作为构造[[HomeObject]].


现在让我们看看它是如何OrdinarySet运作的. 在步骤4c和4d中,规范要求在接收器this而不是proto对象上完成设置操作.

让existingDescriptor成为?[GetOwnProperty]接收机.

如果未定义existingDescriptor,那么

如果IsAccessorDescriptor(existingDescriptor)为true,则返回false.

如果existingDescriptor.[[Writable]]为false,则返回false.

设valueDesc为PropertyDescriptor {[[Value]]:V}.

回来?Receiver.[[DefineOwnProperty]](P,valueDesc).

这些陈述表示OrdinarySet(proto, 3, this)手段this.x = 3.


另一方面,OrdinaryGet 忽略 Receiver.super.x

OrdinaryGet(proto, 'x', this).

OrdinaryGetReceiver在其条款根本没有!所以super.x相当于Object.create(Point.prototype).x,undefined当然.

根据经验,如果转换器和浏览器之间存在差异,浏览器(尤其是Chrome)通常对ECMAScript规范更加忠诚.对于运行时效率,Transpilers通常会交换一些边缘情况正确性.