332
"foo" instanceof String //=> false
"foo" instanceof Object //=> false

true instanceof Boolean //=> false
true instanceof Object //=> false
false instanceof Boolean //=> false
false instanceof Object //=> false

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true

// the tests against Object really don't make sense

Array literals and Object literals match...

[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true

Why don't all of them? Or, why don't they all not?
And, what are they an instance of, then?

It's the same in FF3, IE7, Opera, and Chrome. So, at least it's consistent.

adiga
  • 34,372
  • 9
  • 61
  • 83
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199

10 Answers10

509

Primitives are a different kind of type than objects created from within Javascript. From the Mozilla API docs:

var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)

I can't find any way to construct primitive types with code, perhaps it's not possible. This is probably why people use typeof "foo" === "string" instead of instanceof.

An easy way to remember things like this is asking yourself "I wonder what would be sane and easy to learn"? Whatever the answer is, Javascript does the other thing.

leggetter
  • 15,248
  • 1
  • 55
  • 61
John Millikin
  • 197,344
  • 39
  • 212
  • 226
  • That's true of string literals but not of all literals, such as object, function or array literals. Another reason for the `typeof` check rather than `instanceof` is that the `typeof` test will still work on strings from other frames or windows, or in a (admittedly contrived) situation where the `String` constructor has been overwritten. – Tim Down Jan 07 '10 at 09:52
  • you can turn String object into string literal like type using + ''. (new String('green') + '') instanceof String // returns false – jJ' Jan 25 '12 at 11:32
  • the same also works for Number with +0, Boolean with & true, regexes are a bit special as they differ too much across browsers... – jJ' Jan 25 '12 at 11:43
  • 14
    Every day with a new reason to hate JavaScript is a good day. I know it's long overdue but I thank you for this post. – toniedzwiedz Sep 03 '12 at 22:35
  • 67
    Your terminology is wrong. The word "literal" refers to a syntax for creating data without using a constructor. It doesn't refer to the resulting data. Literal syntax can be used to create both objects and non-objects. The correct term is "primitives", which refer to non-object data. Some data has both primitive and object representations. String is one of those types of data. – gray state is coming Sep 04 '12 at 00:35
  • 16
    FYI, you can create primitives without literal syntax. `(new String()).valueOf();` – gray state is coming Sep 04 '12 at 00:38
  • 11
    Note that `typeof foo === 'string'` is not enough: see axkibe's answer. – Bryan Larsen May 16 '13 at 17:46
  • JSON.parse returns primitives too - `JSON.parse('"foo"') instanceof String` <-- false – Skylar Saveland Oct 01 '14 at 21:49
  • or you can use Object.prototype.toString.call(foo) – jinwei May 11 '15 at 08:58
  • Yet another sign that JS is inconsistent and confusing by design. Why a literal should be a different animal?Why no one cares to fixe it? Maybe it's fixed in ES6? – Nader Ghanbari Nov 03 '16 at 02:22
  • @NaderHadjiGhanbari - This isn't about *literals* being different, it's about *primitive* values being different. The fact that the string was created with a literal is irrelevant, it could as easily have been the return value from `.replace()`, `.charAt()`, `.join()`, `JSON.stringify()`, etc. – nnnnnn Nov 30 '16 at 03:38
  • 2
    In additional, `typeof new String('')` returns `"object"` – Sang Aug 23 '18 at 09:18
124

I use:

function isString(s) {
    return typeof(s) === 'string' || s instanceof String;
}

Because in JavaScript strings can be literals or objects.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
axkibe
  • 2,787
  • 4
  • 19
  • 13
  • 33
    I found something shorte btw. `function isString(s) { return s.constructor === String; }` Works for literals and string objects (at least in V8) – axkibe Dec 06 '11 at 13:05
  • 2
    I use jQuery.type(s) === 'string' (http://api.jquery.com/jquery.type/), jQuery.isArray(), jQuery.isFunction(), jQuery.isNumeric() when it's possible. – Ivan Samygin Aug 08 '14 at 07:21
  • 1
    @axkibe while you're correct, it's [not nearly as performant](http://jsperf.com/typeof-vs-constructor) as `typeof`. – Qix - MONICA WAS MISTREATED Apr 09 '15 at 23:42
  • You can use typeof "?" == String.name.toLowerCase() [but why is [] instanceof Array ?] – QuentinUK May 14 '15 at 18:23
  • Same problem exists for Boolean values: `true instanceof Boolean => false` and yet `typeof true => boolean` ... What even. http://stackoverflow.com/a/4745303/362042 – Dakota Sep 04 '15 at 02:13
  • I use `function isString(s) { return {}.toString.call(s) === "[object String]"; }` which is a null-tolerant function that works for both instances and literals – Joseph Nields Aug 29 '16 at 20:50
  • @QuentinUK because `"?"` is a **primitive and literal** value of `String`. `String`, `Number` and `Boolean` are primitive constructors, the literal default values of that primitive constructors are respectively represented as: `''` for `String`; _(`"?"` is a literal of `String` too)_ `0` for `Number`; `false` for `Boolean`. While *`[]`* and `{}` are **non-primitive literals** for *`Array`* and `Object` constructors respectively! If you have a **primitive literal**, you should use `typeof`. If you have a **non-primitive literal** you can use `instanceof`, since it's more performant! – Daniel Oct 05 '16 at 14:48
  • @QuentinUK See this [answer](http://stackoverflow.com/a/6625960/6399857) – Daniel Oct 05 '16 at 14:53
  • I just learned about this and was surprised by it because I've always just used `typeof x === "string"`. Where are string object instances ever found in the wild? Do people really use `new String("foo")` ? – Adam D Sep 03 '22 at 06:35
75

In JavaScript everything is an object (or may at least be treated as an object), except primitives (booleans, null, numbers, strings and the value undefined (and symbol in ES6)):

console.log(typeof true);           // boolean
console.log(typeof 0);              // number
console.log(typeof "");             // string
console.log(typeof undefined);      // undefined
console.log(typeof null);           // object
console.log(typeof []);             // object
console.log(typeof {});             // object
console.log(typeof function () {}); // function

As you can see objects, arrays and the value null are all considered objects (null is a reference to an object which doesn't exist). Functions are distinguished because they are a special type of callable objects. However they are still objects.

On the other hand the literals true, 0, "" and undefined are not objects. They are primitive values in JavaScript. However booleans, numbers and strings also have constructors Boolean, Number and String respectively which wrap their respective primitives to provide added functionality:

console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0));     // object
console.log(typeof new String(""));    // 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):

console.log(true instanceof Boolean);              // false
console.log(0 instanceof Number);                  // false
console.log("" instanceof String);                 // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number);      // true
console.log(new String("") instanceof String);     // true

As you can see both typeof and instanceof are insufficient to test whether a value is a boolean, a number or a string - typeof only works for primitive booleans, numbers and strings; and instanceof doesn't work for primitive booleans, numbers and strings.

Fortunately there's a simple solution to this problem. The default implementation of toString (i.e. as it's natively defined on Object.prototype.toString) returns the internal [[Class]] property of both primitive values and objects:

function classOf(value) {
    return Object.prototype.toString.call(value);
}

console.log(classOf(true));              // [object Boolean]
console.log(classOf(0));                 // [object Number]
console.log(classOf(""));                // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0)));     // [object Number]
console.log(classOf(new String("")));    // [object String]

The internal [[Class]] property of a value is much more useful than the typeof the value. We can use Object.prototype.toString to create our own (more useful) version of the typeof operator as follows:

function typeOf(value) {
    return Object.prototype.toString.call(value).slice(8, -1);
}

console.log(typeOf(true));              // Boolean
console.log(typeOf(0));                 // Number
console.log(typeOf(""));                // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0)));     // Number
console.log(typeOf(new String("")));    // String

Hope this article helped. To know more about the differences between primitives and wrapped objects read the following blog post: The Secret Life of JavaScript Primitives

nicodemus13
  • 2,258
  • 2
  • 19
  • 31
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • 9
    +1, altough `null` is a [primitive value](http://es5.github.io/#x4.3.2) as well (only the `typeof` operator is confusing) – Bergi Aug 07 '13 at 10:13
43

You can use constructor property:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true
user144049
  • 439
  • 4
  • 2
  • 19
    Note that when testing variables this technique can fail in certain circumstances. There is an implicit reference to the current window in front of `String` and `Boolean` in the above example, so if you are testing the `constructor` property of a string variable created in another window (like a popup or frame) it will _not_ be equal to simply `String`, it will be equal to `thatOtherWindowsName.String`. – Michael Mathews May 10 '10 at 15:11
  • And doesn't instanceof deal with this and return the appropriate boolean result? – Chris Noe Nov 09 '10 at 00:39
  • 5
    this fails if you're passed a descendant of String. – Bryan Larsen May 16 '13 at 17:47
  • 1
    @MichaelMathews: This works to remedy that: `Object.prototype.toString.call('foo') === '[object String]'` – rvighne Jul 20 '14 at 04:34
  • @BryanLarsen and @MichaelMathews Is there any issue in using `d.constructor == String`? E.g. with a loose equality operator. – dotnetCarpenter Jan 28 '16 at 18:21
18
 typeof(text) === 'string' || text instanceof String; 

you can use this, it will work for both case as

  1. var text="foo"; // typeof will work

  2. String text= new String("foo"); // instanceof will work

BoffinBrain
  • 6,337
  • 6
  • 33
  • 59
saurabhgoyal795
  • 1,287
  • 12
  • 12
  • I have been surprised to learn about this. Do people really use instances of String objects in the wild? – Adam D Sep 03 '22 at 06:37
3

This is defined in the ECMAScript specification Section 7.3.19 Step 3: If Type(O) is not Object, return false.

In other word, if the Obj in Obj instanceof Callable is not an object, the instanceof will short-circuit to false directly.

HKTonyLee
  • 3,111
  • 23
  • 34
2

I believe I have come up with a viable solution:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false
2

The primitive wrapper types are reference types that are automatically created behind the scenes whenever strings, num­bers, or Booleans are read.For example :

var name = "foo";
var firstChar = name.charAt(0);
console.log(firstChar);

This is what happens behind the scenes:

// what the JavaScript engine does
var name = "foo";
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
console.log(firstChar);

Because the second line uses a string (a primitive) like an object, the JavaScript engine creates an instance of String so that charAt(0) will work.The String object exists only for one statement before it’s destroyed check this

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. You can create primitive wrapper types manually

Belhadjer Samir
  • 1,461
  • 7
  • 15
-2

For me the confusion caused by

"str".__proto__ // #1
=> String

So "str" istanceof String should return true because how istanceof works as below:

"str".__proto__ == String.prototype // #2
=> true

Results of expression #1 and #2 conflict each other, so there should be one of them wrong.

#1 is wrong

I figure out that it caused by the __proto__ is non standard property, so use the standard one:Object.getPrototypeOf

Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object

Now there's no confusion between expression #2 and #3

mko
  • 21,334
  • 49
  • 130
  • 191
  • 2
    #1 is correct, but it's due to the [property accessor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors), which boxes the primitive value to its respective object type, similar to `Object("str").__proto__` or `Object("str") instanceof String`. – Jonathan Lonowski Jan 12 '15 at 15:30
-8

Or you can just make your own function like so:

function isInstanceOf(obj, clazz){
  return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};

usage:

isInstanceOf('','String');
isInstanceOf(new String(), 'String');

These should both return true.

sth
  • 222,467
  • 53
  • 283
  • 367