1

When I run the following script, I get the error that sub.hello is not a function. Why not? Sub's prototype is Base and Base has the function hello. Since Sub does not have the function hello, shouldn't its prototype then be checked for the function?

function Base() {

}
Base.prototype.hello = function() {
    alert("hello");
}

Sub.prototype = Base;
function Sub() {
    Base.call(this);
}

var sub = new Sub();
sub.hello();
hendryau
  • 426
  • 3
  • 14

2 Answers2

2

A better way to do inheritance in JavaScript is to use the Object.create function:

function Base() {

}
Base.prototype.hello = function() {
    alert("hello");
}

function Sub() {
    Base.call(this);
}
Sub.prototype = Object.create(Base.prototype);

// Restore constructor property
Sub.prototype.constructor = Sub;

var sub = new Sub();
sub.hello();

See jsFiddle

For further reading, check the Mozilla reference

huysentruitw
  • 27,376
  • 9
  • 90
  • 133
  • Don't forget to set `Sub.prototype.constructor = Sub;` since you've overridden Sub's constructor with Base's constructor. – ryeballar Dec 09 '14 at 18:50
  • Yep it still runs, my concern targets cases wherein the constructor property provides useful, cases such as **[this](http://stackoverflow.com/questions/4012998/what-it-the-significance-of-the-javascript-constructor-property#answer-9882720)**. – ryeballar Dec 09 '14 at 18:54
  • @WouterHuysentruit, @ryeballar: Setting `Sub.prototype` to `Object.create(Base.prototype)` override's `Sub`'s constructor with `Base`'s? Also, why do we pass `Base.prototype` in `Object.create()` instead of `Base`? – hendryau Dec 09 '14 at 19:29
  • @hendryau no it doesn't, see http://jsfiddle.net/5stg6hzy/1/, but there is a corner case where code could rely on `prototype.constructor` for whatever reason, see link of ryeballer – huysentruitw Dec 09 '14 at 19:30
  • @hendryau answer to your second question: because you only want to clone the `Base`'s prototype. As calling the `Base`'s constructor is handled in `Sub`'s constructor. – huysentruitw Dec 09 '14 at 19:32
1

The function must exist on the prototype, not on the prototype's prototype.

You've effectively done this:

Sub.prototype.prototype.hello = function () { }

So, instead of Base.prototype.hello, either use Base.hello:

function Base() { }

Base.hello = function() { alert("hello"); }

Sub.prototype = Base;

function Sub() {
    Base.call(this);
}

var sub = new Sub();
sub.hello();

Or make Sub.prototype and instance of Base:

function Base() { }

Base.prototype.hello = function() { alert("hello"); }

Sub.prototype = new Base;

function Sub() {
    Base.call(this);
}

var sub = new Sub();
sub.hello();
user229044
  • 232,980
  • 40
  • 330
  • 338
  • @WouterHuysentruit Downvote posts, not people. Don't be a jerk just because you are wrong and I pointed it out. This is in the rules of this site. I watched your reputation decrease by 1 in the exact instant that you deleted your answer and my received a downvote. – user229044 Dec 09 '14 at 17:53
  • I downvote because you removed hello from Base's prototype. Don't be a smartass and show him the real way of inheriting in js – huysentruitw Dec 09 '14 at 17:55
  • @WouterHuysentruit My post *does* show the "real" way of inheriting in JS. – user229044 Dec 09 '14 at 17:57
  • What will you do if you need to inherit from `Sub`? – huysentruitw Dec 09 '14 at 17:59
  • And now you're executing the Base constructor in `Sub.prototype = new Base;`, you've got it wrong twice now :) – huysentruitw Dec 09 '14 at 18:06
  • @meagar using your first snippet, if I run `var base = new Base(); base.hello();`, `hello` is not defined for `base`, why is that? – hendryau Dec 09 '14 at 18:30
  • @hendryau That's not the case, if you've used the code I've posted: `function Base() { }; Base.prototype.hello = function() { alert("hello"); }; x = new Base; x.hello; // => function () { alert("hello"); }` – user229044 Dec 09 '14 at 18:33
  • @meagar I used the first snippet, not the second. – hendryau Dec 09 '14 at 18:38
  • 1
    @meagar You're first snippet is confusing, if you're trying to create an abstract class that cannot be instantiated then I think its better to create an Object with static methods that will be assigned to Sub's prototype. – ryeballar Dec 09 '14 at 18:57
  • 1
    Furthermore, the second snippet actually invokes the Base constructor as opposed to @WouterHuysentruit answer wherein using `Object.create(Base.prototype)` does not. There's nothing wrong with it, it just invokes the constructor unnecessarily. – ryeballar Dec 09 '14 at 18:58