【问题标题】:Why doesn't reassigning a super method result in that reassigned method being called later?为什么重新分配超级方法不会导致稍后调用重新分配的方法?
【发布时间】:2019-02-14 07:56:26
【问题描述】:

在下面的构造函数中,super.say 被重新分配给一个新函数。在实例上调用.say() 时,将调用新函数。但是,当在调用super.say 的实例上调用不同 方法时,新函数 被调用——而是调用父C 类上的原始函数。为什么会有区别?

class C {
  say() {
    console.log('hello');
  }
}
class D extends C {
  constructor() {
    super()
    super.say = function() {
      console.log('changed');
    }
  }
  shout() {
    super.say()
  }
}

let d = new D()
// changed
d.say()
// hello
d.shout()

【问题讨论】:

  • @CertainPerformance 好吧,我有一个不同的问题(尽管它们的标题似乎相同),请您删除“:duplicate”标签吗?
  • 您的原始问题文本是“我想知道 super 究竟代表什么。谁能告诉我它背后的机制?”,因此关闭 - 编辑后的问题更具体地说明了什么你问的,谢谢。
  • @CertainPerformance 谢谢。 'what is ...' 表达方式过于普遍,我不应该使用它。

标签: javascript


【解决方案1】:

现在我不是 100%,但这是我对正在发生的事情的 2 美分

super 的行为非常怪异,从外观上看,super 在不同的操作中行为不同,这正是正在发生的事情。早些时候我怀疑它,我尝试console.log(super) 并且发生了错误。当我用谷歌搜索找到原因时?我遇到了这样的解释,“它是一个keyword,就像var,你不能按原样记录var关键字”。所以这告诉我们super 不是你的常规对象。

当你做一些事情时会发生什么

constructor() {
  super();
}

这里super()实际上会调用原型C的构造函数,你可以看到console.log(C)导致的结果

C = {
  constructor: f(),
  say: f()
}

但只要你这样做

class D extends C {
  constructor(id) {
    super();

    super.say2 = function() {
      console.log('changed ' + this.id);
    }
}

这里的super.say2 实际上是指this 或D 类的实例(Bejesus 的圣母,这样的事情怎么能逃脱)

我将名称更改为 say2 以准确验证这一点,请参阅下面的代码,我更改了代码以进行测试

class C {
  say() {
    console.log('hello');
  }
}
class D extends C {
  constructor(id) {
    super();

    super.say2 = function() {
      console.log('changed ' + this.id);
    }
    console.log(this)
    console.log(D.prototype)
  }
  shout() {
    super.say()
  }
}

let d = new D(1)
d.say()
d.shout()

当您运行此代码时,您将在控制台中看到的是

这里say2实际上是在D的实例中,而C原型的say在哪里呢?好吧,你自己看看它仍然没有改变

总而言之,当你调用super.say() 时,它会调用C 原型的函数,当你在构造函数中调用super.say = function() 时,它会将其分配给D 的当前实例

通过进一步测试,我了解到 super 被评估为称为 intermedia.value 的东西,因为当我这样做时

shout() {
    super.say2()
}

它给出了错误Uncaught TypeError: (intermediate value).say2 is not a function

总结

  • 当你调用d.say()它实际上是指say函数 实例d
  • 当你调用d.shout()时它引用了sayC的方法

天哪,就在我以为我知道 JS 的时候

【讨论】:

    【解决方案2】:

    简短的回答是super语法。它不是一个具有神奇名称的函数调用(尽管它看起来就是这样!)。

    请参阅 ECMAScript 规范中 SuperPropertySuperCall 的语法产生式:

    • SuperProperty 涵盖 super.somePropertysuper[someExpression] 之类的内容。

    • SuperCall 涵盖super()super(someArgument)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-08
    • 2021-10-03
    • 2018-05-29
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    • 2014-01-21
    相关资源
    最近更新 更多