2

In the below constructor, super.say is reassigned to a new function. When .say() is called on the instance, the new function is called. But when calling a different method on the instance which calls super.say, the new function is not called - the original function on the parent C class is called instead. Why is there a difference?

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
  • 356,069
  • 52
  • 309
  • 320
kakakali
  • 159
  • 1
  • 11
  • @CertainPerformance Well, what I have is a different question (though they seems to be the same by titile), could you please remove the ":duplicate" tag? – kakakali Feb 14 '19 at 08:32
  • Your original question text was "I am wondering what does super exactly represent for. Could anyone please show me the mechanism behind it?", thus the closure - the edited question is much more specific as to what you're asking about, thanks. – CertainPerformance Feb 14 '19 at 08:36
  • @CertainPerformance Thanks. The 'what is ...' expression is something too universal and I shouldn't use that. – kakakali Feb 14 '19 at 08:45

2 Answers2

4

The short answer is that super is syntax. It’s not a function call with a magical name (although that’s what it looks like!).

See the grammar productions for SuperProperty and SuperCall in the ECMAScript spec:

  • SuperProperty covers things like super.someProperty and super[someExpression].

  • SuperCall covers super() and super(someArgument).

Mathias Bynens
  • 144,855
  • 52
  • 216
  • 248
  • Another ECMAScript example of this is [dynamic `import()`](https://developers.google.com/web/updates/2017/11/dynamic-import). It looks like a function call, but it isn’t! – Mathias Bynens Feb 14 '19 at 16:32
  • 1
    Specifically the internal operation MakeSuperPropertyReference shows how this operates: https://tc39.github.io/ecma262/#sec-makesuperpropertyreference. TBH though I am unclear on why it was decided to allow use of SuperProperty as an assignable reference. – Semicolon Feb 15 '19 at 07:50
2

Now I am not 100% but here is my 2 cents on what is going on

super is acting pretty super weird, from the looks of it appeared as super acts different thing in different operation, and that is exactly what is happening. Suspecting it earlier I tried to console.log(super) and error happened. When I googled to find why? I came across the explanation, along the lines of "its a keyword like var and you cannot log var keyword as it is". So that tells us super is not your regular object.

What happens is when you do some thing like

constructor() {
  super();
}

Here super() will actually call the constructor of prototype C, which you can see when you console.log(C) which results into

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

But as soon as you do

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

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

Here super.say2 actually refers to this or instance of class D (Holy Mother of Bejesus, how can somebody get away with something like that)

I changed the name to say2 to verify exactly that, see your code below which I changed to test that

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()

When you run this code what you will see in console is

enter image description here

Here say2 is actually in the instance of D, and where is say of C prototype? well, see for yourself its still there UNCHANGED

enter image description here

So in summary when you call super.say() it calls the function of C prototype, when you do super.say = function() in constructor, it assigns it to current instance of D

At best from further testing what I came to know is super is evaluated as something called intermedia.value because when I did this

shout() {
    super.say2()
}

It gave error Uncaught TypeError: (intermediate value).say2 is not a function

Summary

  • When you called d.say() It actually referred to say function of instance d
  • When you called d.shout() It referred to say method of class C

God, just when I thought I know JS

Umair Abid
  • 1,453
  • 2
  • 18
  • 35