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
- 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
- Primitives are immutable: any property you add will be immediately forgotten.
> var str = "abc"; > str.foo = 123; // write - ignored 123 > str.foo // read undefined
- Primitives are compared by value, they don’t have individual identities: To compare two primitives, one looks at their values, their content. If their values are the same then they are considered equal.
> "abc" === "abc" true
That means that the identity of a primitive is its value, it does not have an individual identity.
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()
> typeof "abc" 'string' > typeof new String("abc") 'object' > "abc" instanceof String false > new String("abc") instanceof String true > "abc" === new String("abc") falseWrapper 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 trueThere 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:
- Returning "object" for null is a well-known bug that can’t be fixed, because it would break existing code. That does not mean that null is actually an object [4].
- typeof allows you to check whether a variable has been declared, without throwing an exception. No function can possibly do that, because you can’t pass it such a variable.
> typeof undeclaredVariable 'undefined' > undeclaredVariable ReferenceError: undeclaredVariable is not defined
- Functions are actually objects; giving them their own category is a bit inconsistent, but sometimes useful.
- Arrays are objects and correctly categorized as such.
instanceof
The instanceof operator is used like this:value instanceof ConstructorThe 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
No comments:
Post a Comment