Olena Horal
Olena Horal

Reputation: 1214

Can’t move a method that uses super

I'm reading this book. Check section "15.6.4.2 Pitfall: A method that uses super can’t be moved"

It states the following

You can’t move a method that uses super: Such a method has the internal slot [[HomeObject]] that ties it to the object it was created in. If you move it via an assignment, it will continue to refer to the superproperties of the original object.

So, I tried to call it with a different object, also assign instance method to a different object but it seems not to work. It refers to new object's properties. Probably, I didn't get correctly what the author means. So, could anyone, please, provide an example?

Hers is a small demo and the code below

class A {
  get a() {
    return 1;
  }

  sayHi() {
    console.log(this.a)
  }
}

class B extends A {
  sayHi() {
    super.sayHi();
  };
}
var obj = {
  a: 4
};
let b = new B();
b.sayHi();
// logs 1

b.sayHi.call(obj);
// logs 4

obj.sayHi = b.sayHi;
obj.sayHi();
// logs 4

Upvotes: 4

Views: 360

Answers (2)

Axel Rauschmayer
Axel Rauschmayer

Reputation: 25741

Your code is OK, because this works when you move a method, but super doesn’t (and your code only really tests this). The following code tests super:

class Bird {
  getName() {
    return 'Bird';
  }
}
class Mammal {
  getName() {
    return 'Mammal';
  }
}
class Human extends Mammal {
  getName() {
    return super.getName();
  }
}
class Duck extends Bird {
}
// Moving method .getName() from Human.prototype to Duck.prototype
Duck.prototype.getName = Human.prototype.getName;

console.log(new Duck().getName()); // 'Mammal' (not 'Bird')

To understand the result, you need to understand how super works – it uses the internal property [[HomeObject]] that is stored in the method itself, it does not rely on this. That is, Human.prototype.getName() internally works as follows:

Human.prototype.getName = Object.assign(
  function me() {
    return me.__HomeObject__.__proto__.getName();
  },
  { __HomeObject__: Human.prototype }
);

More details are explained in the book:

Upvotes: 7

Bergi
Bergi

Reputation: 664385

OP is saying that super.sayHi() will always call A.prototype.sayHi, regardless on what object you call the method. One might have expected

const sayHi = new B().sayHi; // or B.prototype.sayHi

const prototype = {
  sayHi() {
    console.log("not the a property");
  }
};
const myObject = Object.assign(Object.create(prototype), {
  a: "the a property"
});
myObject.sayHi = sayHi;
myObject.sayHi();
// or just sayHi.call(myObject);

to log not the a property - by calling prototype.sayHi through the prototype chain of myObject. But that is not what happens, it logs the a property as normal.

Upvotes: 1

Related Questions