John Resig is Wrong
Yes, the author of jQuery can make mistakes too. This is what he stated:
Each object in JavaScript has an implicit property named constructor
that references the constructor that was used to create the object. And because the prototype is a property of the constructor, each object has a way to find its prototype.
Here are the reasons why his statement is false:
- Not every object has a prototype. Hence these objects don't have any implicit properties either.
- Not every object that has a prototype is created by a constructor function. This however doesn't include object, array and regular expression literals and functions since these objects are implicitly created by constructor functions.
- Not every object that has a prototype and is created by a constructor function has an implicit property named
constructor
.
- Not every object that has a prototype, is created by a constructor and has an implicit property named
constructor
has that property point to the constructor function that created that object.
- Not every object that has a prototype, is created by a constructor and has an implicit property named
constructor
that points to the constructor function that created that object, has a property called prototype
on its constructor function.
- Not every object that has a prototype, is created by a constructor, has an implicit property named
constructor
that points to the constructor function that created that object and has a property called prototype
on its constructor function, has that property point to the prototype of that object.
Let's prove these statements by example to prove that John Resig's statement is false. Since all these statements begin with the assertion "not every object" we only need to find one example of each statement to prove that John Resig's statement is false.
Proof for Statement 1
The Object.create
method can be used to create a new object and set its internal [[prototype]]
property. Hence it can be used to create an object which has no prototype:
var o = Object.create(null); // o has no prototype
The object in the above example has no prototype - it's internal [[prototype]]
property is set to null
. Hence it doesn't have any implicit properties either.
Proof for Statement 2
Now let's create another object p
which inherits from object o
as follows:
var p = Object.create(o); // the prototype of p is o
Hence the object p
has a prototype but it wasn't created by a constructor.
Proof for Statement 3
Alright let's create the object p
from a constructor instead (actually this is precisely how the Object.create
function is implemented):
function F() {} // F is a constructor
F.prototype = o; // objects constructed by F inherit from o
var p = new F; // p is an object which is constructed by F
Here the object p
is created by the constructor F
. However it doesn't have any implicit property named constructor
.
Proof for Statement 4
What if the variable o
was assigned an object literal and then used as the prototype
property of constructor F
?
var o = {}; // object literals inherit from Object.prototype
function F() {} // F is a constructor
F.prototype = o; // objects constructed by F inherit from o
var p = new F; // p is an object which is constructed by F
Now the object p
has an implicit property named constructor
but it points to Object
instead of F
. Hence p.constructor.prototype
points to Object.prototype
instead of o
.
Proof of Statement 5
Perhaps you think the problem is inheritance? Alright, let's do away with inheritance altogether. Starting from scratch:
var p = new F; // p is constructed by F, it inherits from F.prototype
delete F.prototype; // devious isn't it? I love being naughty
function F() {} // declarations are hoisted
Alright so now the object p
inherits from F.prototype
and it has an implicit property named constructor
which points to F
itself. However since we deleted the prototype
property from F
we can't access the prototype of p
via p.constructor.prototype
(it will now return undefined
).
Proof of Statement 6
Let's modify the last example a bit. Instead of deleting F.prototype
we'll set it to something else. For instance:
var o = {}; // object literals inherit from Object.prototype
var p = new F; // p is constructed by F, it inherits from F.prototype
F.prototype = o; // oops, what will happen now?
function F() {} // declarations are hoisted
Now the object p
inherits from F.prototype
and it has an implicit property named constructor
which points to F
itself. However since we set F.prototype
to o
when we access p.constructor.prototype
we'll get o
instead of the original F.prototype
.
Conclusion
As you can see John Resig's statement is totally false. We didn't need 6 examples to prove this. Any one example would suffice. However I wanted to show just how wrong his statement is. Hence I wrote every possible example that I could think of that disproves his statement.
JavaScript is a prototypal object oriented programming language which means that objects inherit from other objects. Constructors are not strictly required to create objects. However they are given undue importance because unfortunately that's the way prototypal inheritance works in JavaScript.
The constructor pattern of prototypal inheritance is often confusing and misleading. In addition it hides the true way of prototypal inheritance which doesn't use constructors (the prototypal pattern of prototypal inheritance). To know more about it read the following answer: https://stackoverflow.com/a/17008403/783743