Update 2012-08-14: Rewrote most of the post, added Sect. 4 explaining
typeof and
instanceof.
This blog post explains that JavaScript has two main kinds of values: primitive values and objects. There are several things one needs to be aware of when working with them.
Kinds of values: primitives versus objects
Values can be partitioned into two main kinds: primitives and objects.
The definition
The usual definition for primitives and objects in JavaScript is:
The following values are primitive.
- Strings: "abc"
- Numbers: 4, 3.57 (all numbers in JavaScript are floating point)
- Booleans: true, false
- null: usually explicitly assigned
- undefined: usually a default value, automatically assigned
All other values are objects. Objects can be partitioned further:
- Wrappers for primitives: Boolean, Number, String. Rarely used directly.
- Creatable by literals. The following literals produce objects that can also be created via a constructor. Use literals whenever you can.
- [] is the same as new Array()
- {} is the same as new Object()
- function() {} is the same as new Function()
- /\s*/ is the same as new RegExp("\\s*")
- Dates: new Date("2011-12-24")
Different natures
You can define primitives and objects by enumerating the primitives and defining objects as non-primitives. But you can also describe what primitives and objects are like. Let’s start with objects.
- Objects are mutable by default:
> var obj = {};
> obj.foo = 123; // write
123
> obj.foo // read
123
- Objects have unique identities and are compared by reference: Every object you create via an expression such as a constructor or a literal is considered different from every other object; a fact that can be observed via the equality operator (===). That operator compares objects by reference: two objects are only equal if they have the same identity. It does not matter whether they have the same content or not.
> {} === {}
false
> var obj = {};
> obj === obj
true
- Variables hold references to objects: Thus, two variables can refer to the same object – changes you make via one variable can be observed via the other variable.
> var var1 = {};
> var var2 = var1;
> var1.foo = 123;
123
> var2.foo
123
As expected, primitives are different:
These last two facts combined mean that there is no way for you to tell whether a variable holds a reference to a primitive or a complete copy. Internally, the former is usually true for strings, the latter for numbers.
Pitfall: Primitive values and their wrappers
Rule:
Ignore wrapper types as much as possible. In contrast to other programming languages such as Java, you will rarely notice them.
The three primitive types string, number and boolean have
corresponding types whose instances are objects:
String,
Number,
Boolean. They are sometimes called
wrapper types and converting between primitive and wrapper is
simple:
- Primitive to wrapper: new String("abc")
- Wrapper to primitive: new String("abc").valueOf()
Primitive values such as
"abc" are fundamentally different from
wrapper instances such as
new String("abc"). For example (
typeof and
instanceof are explained below):
> typeof "abc"
'string'
> typeof new String("abc")
'object'
> "abc" instanceof String
false
> new String("abc") instanceof String
true
> "abc" === new String("abc")
false
Wrapper instances are objects and there is no way of comparing objects in JavaScript, not even via non-strict equals == (which is more lenient than the preferred strict equals ===).
> var a = new String("abc");
> var b = new String("abc");
> a == b
false
> a == a
true
Primitive values don’t have methods of their own
Wrappers are rarely needed in JavaScript, as primitives can be stored
anywhere without wrapping them. But primitives don’t have their own
methods and borrow them from wrappers:
> "abc".charAt === String.prototype.charAt
true
There are two ways that this borrowing is done. The old way is to convert a primitive to a
wrapper, on the fly. The new way (via ECMAScript 5
strict mode) is to transparently use the methods from
the wrapper’s prototype. The following code illustrates the difference [inspired by “
The Secret Life of JavaScript Primitives”].
// Methods in Object.prototype are available to all primitives
Object.prototype.getType = function() {
return typeof this;
};
Object.prototype.getTypeStrict = function() {
"use strict";
return typeof this;
};
console.log("".getType()); // object
console.log("".getTypeStrict()); // string
Categorizing values: typeof and instanceof
If you want to categorize a value, you unfortunately have to be aware of the difference between primitives and objects. The
typeof operator categorizes primitives and distinguishes them from objects. The
instanceof operator categorizes objects and returns
false for any primitive.
typeof
The
typeof operator is mainly used to distinguish primitives from each other and from objects:
> typeof "abc"
'string'
> typeof 123
'number'
> typeof {}
'object'
> typeof []
'object'
typeof returns the following strings:
Value | Result |
Undeclared variables | "undefined" |
undefined | "undefined" |
null | "object" |
Booleans | "boolean" |
Numbers | "number" |
String | "string" |
Functions | "function" |
All other values | "object" |
Comments:
More information on
typeof:
[5] and
[6].
instanceof
The
instanceof operator is used like this:
value instanceof Constructor
The above expression returns
true if
value is an instance of
Constructor. It is equivalent to:
Constructor.prototype.isPrototypeOf(value)
Most objects are instances of
Object, because their prototype chain ends with
Object.prototype.
Primitives are not an instance of anything.
> "abc" instanceof Object
false
> "abc" instanceof String
false
Related content
- JavaScript’s strict mode: a summary
- An easy way to understand JavaScript’s prototypal inheritance
- JavaScript: converting any value to an object
- “null is not an object” – comment on Stack Overflow.
- What is JavaScript’s typeof operator used for?
- Improving the JavaScript typeof operator