es6继承中super的指向问题

问题描述

在看阮一峰大神的ECMAScript 6入门中有关继承的部分的时候,有一个问题:前面提到super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类那么下面的代码

class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3;
    console.log(super.x); // undefined
    console.log(this.x); // 3
  }
}

let b = new B();

当设置super.x = 3时,我的理解相当于是A.prototype.x = 3但实际上好像这里的super就像this一样,虽然文中提到ES6 规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例,但我认为这里的super不是在调用父类的方法

结果

希望大神能帮我解释一下这里super怎么回事,万分感激

阅读 3.2k
3 个回答

super.x = 3;

这个赋值有点特殊。

super 是 A.prototype 。对它的读取来自 A.prototype但是,对它的赋值会进入 this 里。 这是向 super.x 赋值特殊的地方。

读取的时候:console.log(super.x) ,会从 A.prototype 里读,里面没有 x ,于是输出 undefined

==================

以下写给想看一眼标准的:

val.x 的形式会生成一个 Reference ,记录了它是哪来的 (base,这里是 val) ,它叫什么 (referenced name,这里是 "x"),以及其它。

但是 super.x 会额外记录一个信息,就是当前的 this (thisValue)。super.x 的 base 是父类的 prototype 。

赋值的时候,会使用 PutValue(V, W) ,其实 V 就是刚刚提到的 super.x 生成的 Reference,W 是要被赋进去的值。然后它会执行:

base.[[Set]](GetReferencedName(V), W, GetThisValue(V)).

GetReferencedName(V) 与 GetThisValue(V) 分别取出了 Refrence 里记录的 refrenced name ("x"),与 thisValue (保存的 this )。

它是给 base 的 "x" 属性赋值 W 。但是多了一个 thisValue 是干嘛的呢 ...

我们来看真正执行赋值的地方:OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc)

这里 O 是上面的 base (父类的 prototype),P 是属性名 ("x"),V 的要赋的值,Receiver 就是 thisValue

这个算法略长,拿出其中一步(这一步也不短 ...):

3. If IsDataDescriptor(ownDesc) is true, then
    a. If ownDesc.[[Writable]] is false, return false.
    b. If Type(Receiver) is not Object, return false.
    c. Let existingDescriptor be ? Receiver.[[GetOwnProperty]](P).
    d. If existingDescriptor is not undefined, then
        i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
        ii. If existingDescriptor.[[Writable]] is false, return false.
        iii. Let valueDesc be the PropertyDescriptor { [[Value]]: V }.
        iv. Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
    e. Else Receiver does not currently have a property P,
        i. Return ? CreateDataProperty(Receiver, P, V).

可以看到,所有的值,其实都写进了 Receiver ,也就被保存的 this

注:对普通的 val.x ,Reference 没有 thisValue, GetThisValue 直接返回 base 。这样OrdinarySetWithOwnDescriptor 中 O 与 Receiver 是同一个对象。

注2: 读的时候,如果不是 getter ,直接返回 base 里的属性值。

注3: super.func() 里的 this ,用的 thisValue。 val.func()this ,用的 base (也就是 val

发现之前有人和我有一样的疑问,下面的回答挺好的,可以参考(https://segmentfault.com/q/10...), 总之super不是在作为函数而是对象在普通方法(非静态方法)中使用时,可以看作时this在使用

super() 其实是相当于 new A() 只执行 constructor
产生的this用来构建 B实例
super关键字 === A.prototype

你可以这样理解 super 与 super()时的super不是一个东西

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题