1

Here is my code, class B inherits class A:

function A() {
    this.msg = 'meuahah';
    A.prototype.foo = function() {
        alert(this.msg);
    }
}

function B() {
    A.call(this);
    B.prototype.bar = function() {
        A.prototype.foo();
    }
}

a = new A();
a.foo(); // alerts 'meuahah'
b = new B();
b.bar(); // alerts 'undefined'

Why doesn't b.bar() display 'meuahah'?

skurton
  • 331
  • 2
  • 9

4 Answers4

2

Because this is bound to the global object in that case.

You're calling this function

function() {
        alert(this.msg);
    }

when it is not bound to an object. So this will refer to the global object (which is window in the browser) and since that won't have a msg property, it will alert undefined.

When you call a = new A() you create a new object, add msg as a property, and set foo() on its prototype chain. So when you call a.foo() foo is bound to a and this refers to a.

In general you probably want something that looks more like this.

function A() {
    this.msg = 'meuahah';
}

A.prototype.foo = function() {
    alert(this.msg);
}

function B() {
    A.call(this);
}

B.prototype = Object.create(A.prototype);

B.prototype.bar = function() {
    this.foo();
}

You can read more about how this works in javascript from this question

Community
  • 1
  • 1
Ben McCormick
  • 23,365
  • 11
  • 48
  • 70
2

Your prototypal inheritance is not quite right. This is probably more what you want to do:

function A() {
    this.msg = 'meuahah';
}

A.prototype.foo = function() {
    alert(this.msg);
}

function B() {
    A.call(this);
}

B.prototype = new A();
B.prototype.bar = function() {
    this.foo();
}

a = new A();
a.foo(); 
b = new B();
b.bar();

You can override foo in B like this:

B.prototype.foo = function() {
    // Call the original foo method
    A.prototype.foo.apply(this, arguments);
}
Daff
  • 41,847
  • 9
  • 99
  • 113
  • 1
    `B.prototype = A.prototype`. This is kind of dangerous... after setting `B.prototype.bar`, there is now an `A.prototype.bar` as well, which was likely not the intended behavior. – jmar777 Mar 28 '13 at 17:47
  • Good point I guess I blacked out on that for a moment ;) Should be fixed now. – Daff Mar 28 '13 at 17:49
  • 1
    That's definitely better, but the problem now is that you'll have a `B.prototype.msg` (and any other properties set in the `A()` constructor. You would be better off copying each property from `A.prototype` onto `B.prototype`. – jmar777 Mar 28 '13 at 17:59
  • To expand, any behavior in the `A()` constructor is invoked when creating your `B()` constructor's prototype chain, so there's something kind of "wonky" about running constructors prior to any instances actually being created. – jmar777 Mar 28 '13 at 18:01
  • Probably want to be using Object.create rather than either of these options. See my answer. That preserves the prototype without creating an instance or putting `A`'s local properties on B's prototype chain (not harmful in this case but could be if you weren't copying them all anyway) – Ben McCormick Mar 28 '13 at 18:03
2

The reason because b.bar displays undefined is because the this of the foo method is prototype, and prototype doesn't have a msg property.

You basically missed the main point, the inheritance. So, here the code revisited:

function A() {
  this.msg = 'meuahah';
}

A.prototype.foo = function() {
  alert(this.msg);
}

function B() {
    A.call(this);
}

// Set the inheritance! Or better, the prototype's chain,
// so that any instance of B will have methods of A too
B.prototype = Object.create(A.prototype);

B.prototype.bar = function() {
  // Because the inheritance, now B has the A's `foo` method too
  this.foo();
}

// But... We can also override it.
B.prototype.foo = function() {
  // do something
  alert("override");
  // then call the original one
  A.prototype.foo.call(this);
}

Hope it helps to have a better idea about the objects and constructors. I will suggest to investigate on Object.create too, that it's really helpful; and the ES5 methods in general.

The reading Working with Objects it's also a good start, even if it's a bit old.

ZER0
  • 22,173
  • 4
  • 45
  • 51
0

You're just called the A.prototype.foo function, so msg doesn't exist. Here is the output from the console when you console.log(this) inside A.prototype.foo

A {msg: "meuahah", foo: function}
A {foo: function}

The second one is when you call it from inside B, as you can see msg isn't present.

Daniel Imms
  • 43,032
  • 14
  • 130
  • 152