1

I recently saw a similar question while looking at technical interview questions and it got me thinking about object inheritance more generally in JavaScript.

Here is some simple code:

class Car {
  constructor(make,model) {
    this.make = make
    this.model = model
  }

  emitsCarbon() {
    return true
  }

}

class Hybrid extends Car {
  constructor(...args) {
    super(...args)
  }
  emitsCarbon() {
    return false
  }
}

let car1 = new Hybrid('toyota', 'prius')

car1.emitsCarbon() // returns false

What I am curious about is if there is a way to call the original emitsCarbon() method that returns true (from the parent class) in the instance of child class?

My assumption would be no, once it is overridden, I would have to override the method again in the instance of car1 to get it to return true when the function is called.

The lack of knowledge I am seeking to fill is: in JavaScript is it possible to refer back up level in class inheritance and see all the parent class properties (methods, etc.) given an instance of a child class. It looks like this is possible in other languages (e.g., java), however, I do not have as much experience with those languages as much.

Lastly, whether this is useful, i.e., whether one should be more careful about overriding properties that should not be overridden, I am less certain. I think that one shouldn't. However, it is useful to better understand moving up a level in classes and class inheritance hierarchy in general.

This is not a duplicate of: How to call a parent method from child class in javascript?

I understand the calling of a parent method in a child class, however, I do not understand the calling (if at all possible, which it seems not) of a parent method in a child instance.

Shaun
  • 15
  • 8
  • Possible duplicate of [How to call a parent method from child class in javascript?](https://stackoverflow.com/questions/11854958/how-to-call-a-parent-method-from-child-class-in-javascript) – Heretic Monkey Oct 25 '19 at 17:02

4 Answers4

2

It's JavaScript, so you can. There's no classes anyway, just prototypal inheritance with some syntactic sugar over it.

Which one do you want to call: Car's emitsCarbon specifically? That'll be

Car.prototype.emitsCarbon.call(car1);

Your object's class' direct ancestor class' emitsCarbon in general?

car1.__proto__.__proto__.emitsCarbon.call(car1);

(You're not supposed to directly access __proto__, but there's nothing actually stopping you besides the general good practice and guidelines).

Also, hybrids do emit carbon. Just a side note.

mbojko
  • 13,503
  • 1
  • 16
  • 26
  • I am marking this as correct, because this gets at the heart of the issue. I think I understand why you are not supposed to directly access `__proto__ ` (write your subclasses correctly the first time!). Can you point to resources/guides as to why I shouldn't access `__proto__` directly. Also, I know! That's why I chose the example, because it needed to be overridden, i.e., for example's sake I wrote the wrong function. – Shaun Oct 25 '19 at 17:24
  • 1
    MDN is a good place to start (_be_ scared by all that text on pink): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto – mbojko Oct 25 '19 at 17:43
  • Interestingly, that first code snippet is exactly the same as [the accepted answer on the proposed duplicate](https://stackoverflow.com/a/11855048/215552)... – Heretic Monkey Oct 25 '19 at 17:57
  • The first code snippet is not why I marked it as correct. The second code snippet was what I was after. It was going through the child to the parent that is important, not merely calling the function. The second snippet highlights this by pointing through the child instance to call the function in the parent class. I was curious about if it was accessible from the child *at all* not just getting the parent to be called. – Shaun Oct 25 '19 at 18:26
0

I can't believe this isn't a duplicate, but I can't find it (all existing Q/A's deal with old-style constructor functions), so...

Just use super:

class A {
  foo () {
    return 0;
  }
}

class B extends A {
  foo () {
    return 1;
  }

  bar () {
    return super.foo();
  }
}

const b = new B();
b.foo() // 1
b.bar() // 0

There are some limitations, using super will not allow you to modify read-only properties.

See the MDN article for more details.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • This is really helpful (and I know! I read through so many answers on here that did not really answer the problem head on with the new syntax). Supposing the classes cannot be modified (for reasons), is it possible to point up in the instance of b to original class or is Danish Shakeel right, that it is no longer is possible? – Shaun Oct 25 '19 at 17:16
0

The other answer is good for when you can modify the child class.

But since the original post mentions '...instance of child class', as opposed to 'given the child class', then you can do similarly even when you can't modify the child class by using <ParentClass>.prototype.<methodName>.

class A {
  foo () {
    return 0;
  }
}

class B extends A {
  foo () {
    return 1;
  }
}

let b = new B();
console.log(b.foo()); // 1
console.log(A.prototype.foo()); // 0

For methods that require a this context, use call to invoke.

class A {
  constructor(f) {
    this.f = f;
  }

  foo(ff) {
    return this.f + ff + 1;
  }
}

class B extends A {
  foo(ff) {
    return this.f + ff + 2;
  }
}

let b = new B(10);
console.log(b.foo(5)); // 17
console.log(A.prototype.foo.call(b, 5)); // 16
junvar
  • 11,151
  • 2
  • 30
  • 46
  • So, in my example it would be `Car.prototype.emitsCarbon.call(car1)` but that would be no different than simply calling `Car.prototype.emitsCarbon.call()`, or am I mistaken? When I run the code passing no argument in the call method, it still returns true. – Shaun Oct 25 '19 at 17:39
  • Yes that's correct, as explained in my first example, you don't need `call` if your method is effectively static (requires no `this` context). – junvar Oct 25 '19 at 17:50
  • Ah, I see the difference between the two. Thank you! This is helpful, but not exactly what I was looking for. – Shaun Oct 25 '19 at 18:43
0

When a child overrides parent methods, it will always use the overriden version unless you don't use the 'super' keyword in the method definition of the child itself.

Calling a parent method through a child object which is already overriding the method is not possible this way.

Danish Shakeel
  • 258
  • 3
  • 12
  • I think this is the correct answer I am looking for, however another answer shows a work around. – Shaun Oct 25 '19 at 17:13
  • Yes, there are workarounds, thanks to the bad design of the code. But you need to modify the method definition in the inherited class. If there is a real way to achieve the aforementioned, I'd love to learn about it. PS I don't know much about JS. – Danish Shakeel Oct 25 '19 at 17:15