13

In the book Secrets of the JavaScript Ninja, 2013, page 125, it says:

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.

It actually might be one of the most flawed things I heard about JavaScript, and it came from a supposedly expert of JavaScript. Isn't it true that

  1. any JavaScript object "has a way to find its prototype" using the internal [[prototype]] property (as in the ECMA-262 specs, page 32). It is accessible on Chrome and Firefox using __proto__, and in more recently versions of IE, using Object.getPrototypeOf

  2. any object gets to the constructor property by getting it in the prototype object that __proto__ is pointing to. The constructor property is sometimes even not set correctly as some JavaScript libraries or frameworks don't use it at all. constructor is a property of the prototype object, not a property of the object itself:

(as seen in Chrome's developer's tool):

> function Foo() {}
undefined

> var foo = new Foo()
undefined

> foo.hasOwnProperty("constructor")
false

> foo.__proto__.hasOwnProperty("constructor")
true

> foo.__proto__.constructor === Foo
true

Is the above (1) and (2) true? What is the "implicit property named constructor" in JavaScript as in the quoted text? Does it try to mean something like [[prototype]] which is an internal property? But more importantly, I'd like to know whether (1) and (2) above are true and not what the quoted text says it is.

nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 1
    `foo.constructor === Foo // true` – Evan Davis Jun 21 '13 at 13:48
  • @Mathletics `foo.constructor === Foo // true` so what? of course it is true as the `constructor` is obtained by going up the prototype chain, and is exactly the same as `foo.__proto__.constructor` – nonopolarity Jun 21 '13 at 13:51
  • @動靜能量 As far as I know, you are absolutely right. – basilikum Jun 21 '13 at 13:52
  • Yes, 1 and 2 are correct. – Felix Kling Jun 25 '13 at 09:06
  • AFAICT from reading the spec, the constructor property is only defined for built-in objects; and for everything else, all bets are off. – 1983 Jun 30 '13 at 22:46
  • An object has no knowledge of the function that constructed it. That said, the constructor function can be added to the object as a property to the object or one of its prototypes, but at that point, it is a regular (explicit) property. – Havvy Jul 01 '13 at 00:21

3 Answers3

2

The quoted text is very accurate and explains this mechanism very simply.

"Each object in JavaScript has an implicit property named constructor that references the constructor that was used to create the object."

This is absolutely true, as @Mathletics pointed out:

foo.constructor === Foo // true

..."And because the prototype is a property of the constructor, each object has a way to find its prototype."

This also can be understood plainly as read. Getting the prototype from the constructor is a valid way for an instance to find its prototype.

foo.constructor.prototype // Foo {}

And also

foo.constructor.prototype === foo.__proto__ // true

I think that the way the book describes it, is the most proper one of doing it. The "__proto__" property is named with double underscore on each side for a reason. As you pointed out, it is an internal property, and the double underscore is a widely used convention for naming internal properties. It is not "visible" with hasOwnProperty. Not specifically because it is an internal property, but because it is not set directly on the object itself. This might better explain what hasOwnPropery means more clearly:

foo.a = 4;
foo.a; // 4
foo.hasOwnProperty("a"); // true
foo.constructor.prototype.b = 5;
foo.b; // 5
foo.hasOwnProperty("b"); // false
Naor Biton
  • 952
  • 9
  • 14
  • var F = function(){}; F.prototype = {}; var x = new F(); x.constructor === F; // false – 1983 Jun 30 '13 at 22:54
  • Yeah, that's true, and it might look confusing. The thing is, that the _constructor_ property isn't a part of each object directly- `x.hasOwnProperty('constructor') //false` but `x.constructor.prototype.hasOwnProperty('constrcutor') //true` SO, this means that if you set the _prototype_ of _F_, you're also overriding the _constructor_ property of its instances implicitly. If you want to keep your _constructor_ property pointing where you expect it to, make sure to add `F.prototype.constructor = F;` after `F.prototype = {}` in your example. – Naor Biton Jul 01 '13 at 21:36
1

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:

  1. Not every object has a prototype. Hence these objects don't have any implicit properties either.
  2. 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.
  3. Not every object that has a prototype and is created by a constructor function has an implicit property named constructor.
  4. 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.
  5. 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.
  6. 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

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • 3
    Your examples are valid and somewhat amusing, but I find them to be mostly misleading for developers that are trying to understand the meaning of the _constructor_ and _prototype_ properties. JS is a **dynamic** OO language, and that also means you can break its default behavior by using such magic tricks. I could also just call `delete ({}).constructor.prototype.constructor` which will make **all** objects lose their _constructor_ property, thus disproving John's statement, but that would be silly. Perhaps he should've ended his quote with ... _unless you try to break something on purpose_ – Naor Biton Jun 25 '13 at 15:01
  • @NaorBiton JavaScript is a prototypal object oriented programming language. However inheritance in JavaScript is constructor-oriented instead of prototype-oriented. That's the [reason it's so confusing](http://stackoverflow.com/a/17149889/783743 "javascript - Questions regarding prototype function - Stack Overflow"). The code you provided doesn't make all objects lose their `constructor` property. It simply deletes `Object.prototype.constructor`. That's it. If an object `f` inherits from `F.prototype` which in turn inherits from `Object.prototype` then `f.constructor` will still point to `F`. – Aadit M Shah Jun 25 '13 at 15:14
  • You're right about the code I wrote, I should've pointed out that it would remove the _constructor_ from all object _literals_ and others that are inheriting from _Object_ directly. Still, using such examples to prove that John Resig is wrong, could be misleading, because what he describes are valid concepts. I agree that there is more to JS inheritance than constructors, and that you don't have to use them to properly structure your objects (the other answer you referenced shows exactly that), but sometimes constructors are useful with a variety of patterns you can use with JS. – Naor Biton Jun 25 '13 at 15:33
  • @NaorBiton They are only valid under very specific circumstances. Hence beginning the statement with the assertion _"every object in JavaScript"_ is logically wrong. Subject to rigorous mathematical reasoning the statement doesn't hold true. Hence John Resig's statement is misleading. Not mine. – Aadit M Shah Jun 25 '13 at 15:36
  • That is not "precisely" how `Object.create` is implemented. It ignores the second argument and for example in V8 the implementation doesn't create a new function object just to use `new` on it. – Esailija Jun 26 '13 at 08:09
0

How I learned it and what can be observed

Every object has a __proto__ property, every function has an additional prototype property. That prototype is an object itself and has a property called constructor that points to the original function:

function C(){}
console.log(C.hasOwnProperty("prototype")); //true
console.log(C.prototype.hasOwnProperty("constructor")); //true
console.log(C.prototype.constructor === C); //true

When an object is created, the __proto__ property of it is set to point to the prototype property of its constructor function:

var c = new C();
console.log(c.__proto__ === C.prototype) //true

All the information about what c is, does it know from its __proto__ property. That can be observed by simply changing the __proto__ property by hand:

function D(){}
c.__proto__ = D.prototype;
console.log(c.constructor === D) //true
console.log(c instanceof D) //true

So considering all of this, it would be really hard to believe that there is a constructor property from which everything derives. But there still could be in internal constructor property (i.e. __constr__), that we cannot access but which is accessed, when the prototype is requested. At least it would be possible I guess.

One thing that also does confuse me a little, is this:

console.log(c.hasOwnProperty("__proto__")) //false

My guess would be that __proto__ just doesn't get grabbed by the hasOwnProperty method, but maybe someone else can shed some light on this.

FIDDLE

What does ECMA say

Here are also some excerpts from the ECMA Spec:

All objects have an internal property called [[Prototype]]. The value of this property is either null or an object and is used for implementing inheritance. Whether or not a native object can have a host object as its [[Prototype]] depends on the implementation. Every [[Prototype]] chain must have finite length (that is, starting from any object, recursively accessing the [[Prototype]] internal property must eventually lead to a null value). Named data properties of the [[Prototype]] object are inherited (are visible as properties of the child object) for the purposes of get access, but not for put access. Named accessor properties are inherited for both get access and put access

And:

8.12.2 [[GetProperty]] (P)

When the [[GetProperty]] internal method of O is called with property name P, the following steps are taken:

  1. Let prop be the result of calling the [[GetOwnProperty]] internal method of O with property name P.

  2. If prop is not undefined, return prop.

  3. Let proto be the value of the [[Prototype]] internal property of O.

  4. If proto is null, return undefined.

  5. Return the result of calling the [[GetProperty]] internal method of proto with argument P.

My Conclusion

ECMA clearly states that there IS an internal prototype property, which wouldn't really make sense if JavaScript still would access some internal constructor property first, to access something that is already there. Also, everything that can be tested points to the idea of the constructor being a property of the prototype and not the other way around.

So I would say it is safe to say, that this is how it works.

I also reread your quote from Jon Resig. I think what he means with the prototype is a property of the constructor is the prototype property that we can directly access and that every function has. He is also not super specific here. I guess he just wanted a simple explanation and didn't want to confuse people right off.

basilikum
  • 10,378
  • 5
  • 45
  • 58
  • I think `c.hasOwnProperty("__proto__")` is false because `__proto__` is an internal property and it is not to be checked by using `hasOwnProperty` -- or `hasOwnProperty` won't report the internal property – nonopolarity Jun 21 '13 at 14:24
  • @動靜能量 yes, i guess that's it. – basilikum Jun 21 '13 at 14:34