I understand your problem. The slide you mentioned - John Resig's 76th slide, has already been explained in the following answer:
https://stackoverflow.com/a/17768570/783743
The problem in your case is a classic problem poeple face when first learning JavaScript; and this problem arises not because of your ineptitude to understand prototypal inheritance but because of the way prototypal inheritance has been portrayed in JavaScript.
The Two Faces of Prototypal Inheritance
Prototypal inheritance can be implemented in one of two ways. Hence prototypal inheritance is analogous to a coin. It has two faces:
- The prototypal pattern of prototypal inheritance
- The constructor pattern of prototypal inheritance
The first pattern is the common or the true pattern of prototypal inheritance. Languages like Self and Lua employ the prototypal pattern of prototypal inheritance.
The second pattern was designed to make prototypal inheritance look like classical inheritance. It's only used in JavaScript and it hides the way prototypal inheritance works making it difficult to understand it.
I've discussed prototypal inheritance in depth in my article on Why Prototypal Inheritance Matters and I recommend that you read it carefully.
Understanding Prototypal Inheritance
Prototypal inheritance is all about objects inheriting from other objects. There are no classes in prototypal inheritance. Only objects. For example, consider:
var boy = {};
var bob = Object.create(boy);
In the above example the object bob
inherits from the object boy
. In simple English:
Bob is a boy.
In classical inheritance you would write the above as:
class Boy {
// body
}
Boy bob = new Boy;
As you can see prototypal inheritance is very flexible. In prototypal inheritance all you need are objects. Objects behave as both classes and as instances. An object which behaves as a class is called a prototype. Hence boy
is a prototype of bob
.
Constructing an Object from a Prototype
Now consider we have an object called rectangle
:
var rectangle = {
width: 10,
height: 5,
area: function () {
return this.width * this.height;
}
};
We may use rectangle
as an instance as follows:
console.log(rectangle.area());
On the other hand we may also use rectangle
as a prototype:
var rect2 = Object.create(rectangle);
rect2.width = 15;
rect2.height = 6;
console.log(rect2.area());
However it's a pain to keep defining the width
and height
on every object that inherits from rectangle
. Hence we create a constructor:
rectangle.create = function (width, height) {
var rect = Object.create(this);
rect.height = height;
rect.width = width;
return rect;
};
Now you can create instance of rectangle
as follows:
var rect2 = rectangle.create(15, 6);
console.log(rect2.area());
This is the prototypal pattern of prototypal inheritance because in this method the focus is on the prototype and not on the constructor function create
.
The Constructor Pattern
The same thing can be done in JavaScript using the constructor pattern as follows:
function Rectangle(width, height) {
this.height = height;
this.width = width;
}
var rectangle = Rectangle.prototype;
rectangle.width = 10;
rectangle.height = 5;
rectangle.area = function () {
return this.width * this.height;
};
var rect2 = new Rectangle(15, 6);
console.log(rect2.area());
The problem with the constructor pattern is that the focus is on the constructor instead of the prototype. Hence people think that rect2
is an instance of Rectangle
which is false. In JavaScript objects inherit from other objects and not from constructors.
The object rect2
is an instance of Rectangle.prototype
at the time rect2
was created. It's not an instance of Rectangle
.
Your Problem
In your question you define Foo
as follows:
var Foo = function() {
this.report('Foo');
};
Foo.report = function(i) {
alert('report: ' + i);
};
Hence when you create an object from Foo
using new
(i.e. new Foo
) the object inherits from Foo.prototype
. It doesn't inherit from Foo
. Hence the object doesn't have any property called report
and thus throws an error.
In your question you also define Bar
:
var Bar = function() {
this.report('Bar');
};
Bar.prototype = Foo; // Right; it's not 'new Foo()'
Here the prototype
of Bar
is Foo
. Hence objects created from Bar
will inherit from Bar.prototype
or Foo
. Hence those objects inherit the report
function from Foo
.
I know. It's very confusing, but that's the way prototypal inheritance is implemented in JavaScript. Don't forget to read my blog post:
Why Prototypal Inheritance Matters