javascript es6 super 不理解

发布于 2022-09-07 08:17:17 字数 977 浏览 49 评论 0

本人新手, 最近在看阮一峰老师的es6里面class的继承这一章, 对super一些概念不理解, 具体如下:
在阮一峰老师的博客里有这样一段代码:

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

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

let b = new B();

阮一峰老师是这么说的

由于this指向子类实例,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。
上面代码中,super.x赋值为3,这时等同于对this.x赋值为3

这里我很不理解, 为什么使用super.x进行赋值以后就等同于this.x,

我的理解是:
根据阮一峰老师前面说的

super作为对象时,在普通方法中,指向父类的原型对象

那么这里的super.x = 3实际上应该就是A.prototype.x = 3, 那么对于子类B应该是没有影响的, 所以个人理解结果应该是2
但是浏览器跑出来的结果却和阮老师的结果一样是3, 所以请问应该如何理解

希望能有前辈给一个清晰的解答, 谢谢了!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

乱世争霸 2022-09-14 08:17:17

题主看书看仔细些

第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

ES6 规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。

这两句话连在一起,不矛盾!意思就是:

意思是:

在子类普通方法中通过super调用父类的方法时

super指向父类的原型对象,但是父类的方法中的this指向当前的子类实例。

super.x = 3;

这里super指向父类的原型对象,没错!

但是底层并不是直接执行

A.prototype.x = 3

而是转换了底层的this,最终效果类似于:

this = 3

代码验证:

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

class B extends A {
  constructor() {
    super()
    this.x = 2
    Object.defineProperty(A.prototype, 'x', {
      set: function(val) {
        console.log(this, val)
         //B {x: 2} 3,证明对super的赋值最终作用到了B {x: 2}身上,也就是新生成的实例,this
      }
    })
    super.x = 3
    console.log(this.x) // 3
  }
}

let b = new B()

你再看看阮老师举的函数调用的例子,这个例子就更清楚了,因为函数可以用 call

clipboard.png

代码:

class A {
  constructor() {
    this.x = 1
  }
  print() {
    console.log(this.x)
  }
}

class B extends A {
  constructor() {
    super()
    this.x = 2
  }
  m() {
    // super.print()//上下两句等价的,所以上面这句隐含转换了this
    super.print.call(this)
  }
}

let b = new B()
b.m() // 2

super.print() 等价于super.print.call(this),因为底层隐含转换了this

所以,最终有了下面的解释:

由于this指向子类实例,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。

嘿咻 2022-09-14 08:17:17

调用super() 时会在类中生成一个新的上下文this, 所以阮说给super赋值,就是赋值给this,实际开发中并不应该给super赋值,super 关键字用于调用对象的父对象上的函数

深海夜未眠 2022-09-14 08:17:17

如果通过super对某个属性赋值,这时super就是this

这样看的话就好理解了啊,在对super进行某个属性赋值时,这个时候 super 就是 this,在别的时候,super 指向的应该是父类,这样就可以解释了。

半﹌身腐败 2022-09-14 08:17:17

super()并不是通过prototype实现继承的,而是类似于传统的class方式来实现。也就是子类不能修改父类的属性。我猜想,当 super.x = 3 时,会将3赋值给this,然后删除了super.x。由此无法反向给父类赋值

狼亦尘 2022-09-14 08:17:17

前几天刚好在学习这个,看到文档里得出3我也很疑惑,自己运行了一下发现是等于2的,难道只有我一个人得出了2?

class A {
  constructor() {                             // constructor方法默认返回实例对象(即this)
    this.x = 1;                               // 父类的实例属性
    console.log('子类B的实例:', this);        // B {x: 1},执行两次,因为下面执行了super()两次,返回的是子类B的实例。
  }
  foo() {
    return 10;
  }
}
console.log('父类的原型对象:', A.prototype);  // {constructor: ƒ, foo: ƒ}。类的所有方法都定义在类的prototype属性上面。

class B extends A {
  constructor() {
    super();                                  // 2. super使用的第一种情况,super作为函数调用时,虽然代表了父类A的构造函数,但是返回的是子类B的实例。
    console.log(super() === this);            // 3. super返回的是子类的实例对象,this代表子类的实例对象,所以判断它们相等返回true。
    this.x = 2;                               // 1. this代表实例对象,就是下面new出来的实例对象b。(按照123的顺序理解)
    console.log('=====验证=====', this);      // B {x: 2}

    // 题主主要问的是super当做对象使用时的情况,super作为对象时,在普通方法中,指向父类的原型对象。
    console.log(super.foo());                 // 10,相当于A.prototype.foo()
    // 由于super指向父类的原型对象,所以定义在父类实例上的方法或属性(也就是父类中的this.x = 1),是无法通过super调用的。
    console.log(super.x);                     // undefined,实际读取的是A.prototype.x,所以返回undefined。                     
    Object.defineProperty(A.prototype, 'x', { // 这里难道不是说明,执行super.x = 3;的时候,实际就是执行的A.prototype.x。
      set(val) {
        console.log(val)                      // 先输出'测试',后输出3。如果不是执行的A.prototype.x,就不会进到这里,不会有输出。
      }
    });
    super.x = '测试';
    super.x = 3;
    console.log('最终结果', this.x);          // 最终结果 2
  }
}
let b = new B();
console.log('=====验证=====', b);            // B {x: 2}

控制台:
图片描述

个人理解和题主一样,super指向的就是父类的原型对象,所以在super.x上赋值,不会影响到指向实例对象的this,所以应该还是2,实际运行结果也是2。
为什么有人得到2有人得到3,可能是es版本的原因,具体还需仔细研究,希望明白的大神不吝赐教。

羁拥 2022-09-14 08:17:17

只说说个人理解,仅供参考;阮一峰老师说了:
1、在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
2、个人理解在super.x=3 的时候,其实并不是直接赋值的,而是调用了super对象内的的set函数,该方法里改变this指向了当前实例。
3、super本身没有set/get,不过他却继承了object的get/set方法

芯好空 2022-09-14 08:17:17

由于this指向子类实例,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。
上面代码中,super.x赋值为3,这时等同于对this.x赋值为3

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

class B extends A {
  constructor() {
    super();
    this.x = 2;
    console.log(super.x)// 如果上述成立 那么super.x=2 但是结果是undefined
    super.x = 3;
    console.log(this.x); // 3
  }
}

let b = new B();

我并不理解super的具体实现,但是按照这逻辑加了一句代码,结果显然是不成立。弱弱的怀疑一下这不是通过现象反猜的吧?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文