I'm not sure that article is the best way to understand what's going on here - it's a great technical explanation, but perhaps not the best way to get an intuitive understanding.
Let's step back and work this through.
A quick look at property lookup
One way to understand prototypal inheritance is to think of it as way to say "if I don't have it, look over there".
Say you've got an object and try to access a property that doesn't exist, JS will return the value undefined
:
var x = {};
x.foo //=> undefined
All objects inherit from Object.prototype
, so look what happens if we modify it:
var x = {};
x.foo //=> undefined
Object.prototype.foo = 'hello there';
x.foo //=> 'hello there';
What happened? When we initially create x, JavaScript sets up an internal [[Prototype]]
property that points to Object.prototype
. Effectively, there is a lookup algorithm that looks something like (pseudo-code):
Lookup(obj, prop) =
if HasProperty(object, property)
return GetPropertyValue(object, property)
else if HasPrototype(object)
return Lookup(PrototypeOf(object), property)
else
return undefined
In other words, start with the initial object, check for the property, if it doesn't have it, follow the prototype chain to keep looking for it. If we hit the end of the prototype chain, the property must be undefined.
So what about the new
operator?
The new
operator gives us a way to:
- dynamically set the prototype of an object to something other than
Object.prototype
- do some initialization stuff when we create an object
NOTE: in ES5, we also have Object.create
which gives you 1, but not 2.
When you say new Foo(a, b)
, here's what happens:
- we make a new object that has its internal
[[Prototype]]
set to Foo.prototype
.
- we run the function
Foo
(its just a normal function) with its context (think this
) set to the new object we just made
- we return the new object after the function finishes (actually, if the function explicitly returns a value, we just return that value, but most of the time, we won't be doing that).
But wait, where did Foo.prototype
come from?
Let's see - run the following in the console:
function Foo() {}
typeof Foo.prototype //=> "object"
When we create a function in JS, it comes with an object attached to its prototype
property. It's just an object, like any other, so you can manipulate it, set/delete properties, even completely overwrite it (which the mentioned article shows an example of).
For example:
function Foo() {}
Foo.prototype.answer = 42;
var foo1 = new Foo();
var foo2 = new Foo();
foo1.answer //=> 42
foo2.answer //=> 42
// If you want you can change foo2's answer
foo2.answer = 'something else';
// Foo.prototype is unchanged
Foo.prototype.answer //=> 42
foo1.answer //=> 42 (still getting its answer from the prototype)
foo2.answer //= 'something else'
Getting back to the original question
Continuing with the foo example from above, what the original article was referring to is that foo1
and foo2
don't have prototype
properties set on them:
foo1.prototype //=> undefined
foo2.prototype //=> undefined
NOTE: there is a non-standard __proto__
property that many JS engines provide that will give you an object's prototype, and in ES5, you also have Object.getPrototypeOf to get access to a given object's prototype.
Relevant links: