Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are JavaScript primitives not instanceof Object?

Today I happened to have too much time to kill and I played a bit with the Node (v0.10.13) command line:

> 1 instanceof Object
false
> (1).__proto__
{}
> (1).__proto__ instanceof Object
true
> (1).__proto__.__proto__ === Object.prototype
true

Now, according to MDN, what instanceof does is:

The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

But clearly Object.prototype IS in 1's prototype chain. So why is 1 instanceof Object false? Perhaps because 1 is a primitive not an object to begin with?

Okay, I accept that, and I did more tests:

> (1).__proto__ === (2).__proto__
true
> 'a'.__proto__ === 'b'.__proto__
true
> (1).__proto__ === 'a'.__proto__
false
> (1).__proto__.__proto__ === 'a'.__proto__.__proto__
true
> (1).__proto__.type = 'number'
'number'
> 'a'.__proto__.type = 'string'
'string'
> (2).type
'number'
> (1.5).type
'number'
> 'b'.type
'string'

So apparently all number primitives inherit from one object, and all string primitives inherit from another object. Both these 2 objects inherit from Object.prototype.

Now the question is, if numbers and strings are considered primitives, why inherit them from other objects? Or inversely, as they inherit from other objects, why not consider them objects too? It seems nonsensical to me that the child of an object isn't an object..

By the way, I have also tested these in Firefox 22 and got the same result.

like image 236
Gary Chang Avatar asked Jul 30 '13 05:07

Gary Chang


People also ask

What is the difference between primitive and object in JavaScript?

Primitives are not composed of any other data types, whereas objects may be composed of other objects. In fact, nearly all objects in JavaScript are a subclass of the Object class. Primitive values are immutable (i.e. they cannot be changed). In contrast to this, objects are not immutable by default .

When does a primitive value become an object?

As you can see when primitive values are wrapped within the Boolean, Number and String constructors respectively they become objects. The instanceof operator only works for objects (which is why it returns false for primitive values):

Why can’t instanceof be used to create temporary objects?

Because instanceof doesn’t actually read anything, no temporary objects are created, and it tells us the ­values aren’t instances of primitive wrapper types. You can create primitive wrapper types manually

Why does instanceof return false in JavaScript?

The instanceof operator returns false because a temporary object is created only when a value is read. Because instanceof doesn’t actually read anything, no temporary objects are created, and it tells us the ­values aren’t instances of primitive wrapper types.


1 Answers

You have been tricked by a mechanism commonly known as "boxing" (c# related article, java related article) which mesmerises all who come across it. You had the correct answer in the beginning:

Perhaps because 1 is a primitive not an object to begin with?

Exactly so. However, how can primitives ever be able to contain methods? How can they contain properties? After all, in js, they are represented at the lowest level possible (see #4.3.2). To make these values actually useful, whenever you do primitive.property, the following happens (#11.2.1):

Object(primitive).property;

In other words, js has automatic boxing. This can be proven using one of my favourite tricks:

var primitive = 'food';
primitive.isPizza = true; //yummy
console.log(primitive.isPizza); //undefined. where did my pizza go!?

primitive.isPizza disappeared because of this boxing:

var primitive = 'food';
Object(primitive).isPizza = true;
console.log(Object(primitive).isPizza);

The boxed primitive is its own unique snowflake - when you box it a second time, it does not refer to the same thing. The boxed values are quickly GCd and forgotten in the mists of time.

This does not happen if your primitive isn't, well, a primitive:

var obj = new String('food');
obj.isPizza = true;
console.log(obj.isPizza); //true

Does this mean you should only use objects, never primitives? Nope, for the simple reason that the times you do need to store meta-data on primitives are very far and few, and objects complicate things:

obj === primitive; //false, obj is an object, primitive is a primitive
like image 183
Zirak Avatar answered Nov 08 '22 19:11

Zirak