4.4 Primitive Types and Reference TypesThe next topic we need to consider is the content of variables. We often say that variables have or contain values. But just what is it that they contain? To answer this seemingly simple question, we must look again at the data types supported by JavaScript. The types can be divided into two groups: primitive types and reference types. Numbers, boolean values, and the null and undefined types are primitive. Objects, arrays, and functions are reference types. A primitive type has a fixed size in memory. For example, a number occupies eight bytes of memory, and a boolean value can be represented with only one bit. The number type is the largest of the primitive types. If each JavaScript variable reserves eight bytes of memory, the variable can directly hold any primitive value.[3]
Reference types are another matter, however. Objects, for example, can be of any length -- they do not have a fixed size. The same is true of arrays: an array can have any number of elements. Similarly, a function can contain any amount of JavaScript code. Since these types do not have a fixed size, their values cannot be stored directly in the eight bytes of memory associated with each variable. Instead, the variable stores a reference to the value. Typically, this reference is some form of pointer or memory address. It is not the data value itself, but it tells the variable where to look to find the value. The distinction between primitive and reference types is an important one, as they behave differently. Consider the following code that uses numbers (a primitive type): var a = 3.14; // Declare and initialize a variable var b = a; // Copy the variable's value to a new variable a = 4; // Modify the value of the original variable alert(b) // Displays 3.14; the copy has not changed There is nothing surprising about this code. Now consider what happens if we change the code slightly so that it uses arrays (a reference type) instead of numbers: var a = [1,2,3]; // Initialize a variable to refer to an array var b = a; // Copy that reference into a new variable a[0] = 99; // Modify the array using the original reference alert(b); // Display the changed array [99,2,3] using the new reference If this result does not seem surprising to you, you're already well familiar with the distinction between primitive and reference types. If it does seem surprising, take a closer look at the second line. Note that it is the reference to the array value, not the array itself, that is being assigned in this statement. After that second line of code, we still have only one array object; we just happen to have two references to it. If the primitive versus reference type distinction is new to you, just try to keep the variable contents in mind. Variables hold the actual values of primitive types, but they hold only references to the values of reference types. The differing behavior of primitive and reference types is explored in more detail in Section 11.2. You may have noticed that I did not specify whether strings are primitive or reference types in JavaScript. Strings are an unusual case. They have variable size, so obviously they cannot be stored directly in fixed-size variables. For efficiency, we would expect JavaScript to copy references to strings, not the actual contents of strings. On the other hand, strings behave like a primitive type in many ways. The question of whether strings are a primitive or reference type is actually moot, because strings are immutable: there is no way to change the contents of a string value. This means that we cannot construct an example like the previous one that demonstrates that arrays are copied by reference. In the end, it doesn't matter much whether you think of strings as an immutable reference type that behaves like a primitive type or as a primitive type implemented with the internal efficiency of a reference type. |