3.12 Primitive Data Type Wrapper ObjectsWhen we discussed strings earlier in this chapter, I pointed out a strange feature of that data type: to operate on strings, you use object notation. For example, a typical operation involving strings might look like the following: var s = "These are the times that try people's souls."; var last_word = s.substring(s.lastIndexOf(" ")+1, s.length); If you didn't know better, it would appear that s was an object and that you were invoking methods and reading property values of that object. What's going on? Are strings objects, or are they primitive data types? The typeof operator (see Chapter 5) assures us that strings have the data type "string", which is distinct from the data type "object". Why, then, are strings manipulated using object notation? The truth is that a corresponding object class is defined for each of the three key primitive data types. That is, besides supporting the number, string, and boolean data types, JavaScript also supports Number, String, and Boolean classes. These classes are wrappers around the primitive data types. A wrapper contains the same primitive data value, but it also defines properties and methods that can be used to manipulate that data. JavaScript can flexibly convert values from one type to another. When we use a string in an object context -- i.e., when we try to access a property or method of the string -- JavaScript internally creates a String wrapper object for the string value. This String object is used in place of the primitive string value; the object has properties and methods defined, so the use of the primitive value in an object context succeeds. The same is true, of course, for the other primitive types and their corresponding wrapper objects; we just don't use the other types in an object context nearly as often as we use strings in that context. Note that the String object created when we use a string in an object context is a transient one -- it is used to allow us to access a property or method and then is no longer needed, so it is reclaimed by the system. Suppose s is a string and we determine the length of the string with a line like this: var len = s.length; In this case, s remains a string; the original string value itself is not changed. A new transient String object is created, which allows us to access the length property, and then the transient object is discarded, with no change to the original value s. If you think this scheme sounds elegant and bizarrely complex at the same time, you are right. Typically, however, JavaScript implementations perform this internal conversion very efficiently, and it is not something you should worry about. If we want to use a String object explicitly in our program, we have to create a nontransient one that is not automatically discarded by the system. String objects are created just like other objects, with the new operator. For example: var s = "hello world"; // A primitive string value var S = new String("Hello World"); // A String object Once we've created a String object S, what can we do with it? Nothing that we cannot do with the corresponding primitive string value. If we use the typeof operator, it tells us that S is indeed an object, and not a string value, but except for that case, we'll find that we can't normally distinguish between a primitive string and the String object.[6] As we've already seen, strings are automatically converted to String objects whenever necessary. It turns out that the reverse is also true. Whenever we use a String object where a primitive string value is expected, JavaScript automatically converts the String to a string. So if we use our String object with the + operator, a transient primitive string value is created so that the string concatenation operation can be performed:
msg = S + '!'; Bear in mind that everything we've discussed in this section about string values and String objects applies also to number and boolean values and their corresponding Number and Boolean objects. You can learn more about these classes from their respective entries in the core reference section of this book. In Chapter 11, we'll see more about this primitive type/object duality and about automatic data conversion in JavaScript. |