Randomblue
Randomblue

Reputation: 116263

Instanceof inconsistency

Could someone please explain the following?

[] instanceof Array; // true
'' instanceof String; // false

Upvotes: 15

Views: 482

Answers (4)

Halcyon
Halcyon

Reputation: 57709

I've done some digging and I suppose it has to do with string interning which is a compiler optimization.

Okay, ready for some gotchas? :D

"abc" == "abc"; // true
"abc" === "abc"; // true

I suppose this is true because of "string interning" which coincidentally also makes a lot of sense, conceptually (yay for getting 'strings' right).

new String("abc") == new String("abc"); // false
new String("abc") === new String("abc");    // false

This makes sense if you assume a String is an object and an object is only equal to itself and not equal to object with similar internal state. Like in Java (or how it used to be anyway).

And now for the kicker:

(new String("abc")).substr(0,3) === (new String("abc")).substr(0,3); // true!

So apparently the JavaScript interpreter will always prefer string interning over the use of the String object.

Then I must ask, what is the use of the String object? Apparently it doesn't play nice with its friends.

Upvotes: 1

user1106925
user1106925

Reputation:

It's because '' is primitive, not an object.

Some primitives in JavaScript can have an object wrapper. These are created when you make an instance of the wrapper using the built in constructor with new.

The new is typically necessary because often times the function will coerce to a primitive if you exclude new.

typeof new String('');  // "object"
typeof String('');      // "string"
typeof '';              // "string"

The primitives that have Object wrappers are string, number and boolean.

The primitives that do not are null and undefined.

Upvotes: 11

Jon Newmuis
Jon Newmuis

Reputation: 26492

Note the following:

"" instanceof String;             // => false
new String("") instanceof String; // => true

instanceof requires an object, but "" is a string literal, and not a String object. Note the following types using the typeof function:

typeof ""             // => "string"
typeof new String("") // => "object"
typeof []             // => "object"
typeof new Array()    // => "object"

Upvotes: 14

Ry-
Ry-

Reputation: 224862

'' isn't an instance of anything; it's a primitive type, and it works in much the same way as 5.5 or true. There's a difference between a string primitive and a String object. See:

new String('') instanceof String; // true

Anything created with new String(), new Number() or new Boolean() is an object wrapper around the primitive type, and they're not the same.

To check for strings, etc., use typeof instead:

typeof '' === 'string'; // true

To check for both, use this:

Object.prototype.toString.call('') === '[object String]'; // true
Object.prototype.toString.call(new String('')) === '[object String]'; // true

There are a couple of reasons to use Object.prototype.toString.call for general-use code, for arrays, strings, numbers and booleans. They are:

  1. For strings, numbers, and booleans, people may pass instances of the wrapper objects instead of the primitive types. They usually function in the same way (with an implicit valueOf()) and so you should accept them if writing library code.
  2. For arrays, if you receive an array from another window (say from an <iframe>) then using instanceof Array will return false. The Object.prototype.toString.call method works for all purposes.

This is what jQuery and other large, popular libraries do.

Upvotes: 3

Related Questions