In the earlier Strings tutorial and less so in the Of Pizza, Types, Primitives, and Objects tutorial, you got a sneak peek at something that is probably pretty confusing. I've stated many times that primitives are very plain and simple. Unlike Objects, they don't contain properties that allow you to fiddle with their values in interesting (or boring) ways. Yet, as clearly demonstrated by all the stuff you can do with strings, your primitives seem to have a mysterious dark side to them:
var greeting = "Hi, everybody!!!"; var shout = greeting.toUpperCase(); //where did toUpperCase come from?
As you can see from this brief snippet, your greeting variable, which stores a primitive value in the form of text, seems to have access to the toUpperCase method. How is this even possible? Where did that method come from? Why am I here? Answers to confusing existential questions like this will make up the bulk of what you see in this page. Also, I apologize for writing that previous sentence in passive voice. Happen again it won't.
Strings Aren't the Only Problem
Because of how cute they are, it's easy to pick on strings as the main perpetrator of this primitive/Object confusion. As it turns out, many of the built-in primitive types are involved in this racket as well. Below is a table of the built-in Object types with the guilty parties that also exist as primitives highlighted:
|Type||What it does|
|Array||helps store, retrieve, and manipulate a collection of data|
|Boolean||acts as a wrapper around the boolean primitive; still very much in love with true and false|
|Date||allows you to more easily represent and work with dates|
|Function||allows you to invoke some code among other esoteric things|
|Math||the nerdy one in the group that helps you better work with numbers|
|Number||acts as a wrapper around the number primitive|
|RegExp||provides a lot of functionality for matching patterns in text|
|String||acts as a wrapper around the string primitive|
Whenever you are working with boolean, number, or string primitives, you have access to properties their Object equivalent exposes. In the following sections, you'll see what exactly is going on.
Let's Pick on Strings Anyway
Just as you were taught by your parents growing up, you typically use a string in the literal form:
var primitiveText = "Homer Simpson";
As you saw in the table earlier, strings also have the ability to be used as objects. There are several ways to create a new object, but the most common way to create an object for a built-in type like our string is to use the new keyword followed by the word String:
var name = new String("Homer Simpson");
The String in this case isn't just any normal word. It represents what is known as a constructor function whose sole purpose is to be used for creating objects. Just like there are several ways to create objects, there are several ways to create String objects as well. The way I see it, knowing about one way that you really shouldn't be creating them with is enough.
Anyway, the main difference between the primitive and object forms of a string is the sheer amount of additional baggage the object form carries with it. Let's bring our silly visualizations back. Your primitiveText variable and its baggage looks as follows:
There really isn't much there. Now, don't let the next part scare you, but if we had to visualize our String object called name, here is what that would look like:
You have your name variable containing a pointer to the text, Homer Simpson. You also have all of the various properties and methods that go with the String object - things you may have used like indexOf, toUpperCase, and so on. You'll get a massive overview of what exactly this diagram represents in a future tutorial, so don't worry yourself too much about what you see here. Just know that the object form of any of the primitives carries with it a lot of functionality.
Why This Matters
var game = "Dragon Age: Origins";
The game variable is very clearly a string primitive that is assigned to some literal text. If I want to access the length of this text, I would do something as follows:
var game = "Dragon Age: Origins"; alert(game.length);
This transformation only happens for primitives. If you ever explicitly create a String object, then what you create is permanently kept as an object. Let's say you have the following:
var gameObject = new String("Dragon Age:Origins");
In this case, our gameObject variable very clearly points to something whose type is Object. This variable will continue to point to an Object type unless you modify the string or do something else that causes the reference to be changed. The primitive morphing into an object and then morphing back into a primitive is something unique to primitives. Your objects don't partake in such tomfoolery.
You can easily verify everything I've said by examining the type of your data. That is done by using the typeof keyword. Here is an example of me using it to confirm everything I've just told you about:
var game = "Dragon Age: Origins"; alert("Length is: " + game.length); var gameObject = new String("Dragon Age:Origins"); typeof game //string typeof game.length //number typeof gameObject //Object
Now, aren't you glad you learned all this?
Hopefully this brief explanation helps you to reconcile why your primitives behave like objects when they need to. At this point, you might have a different question around why anybody would have designed a language that does something this bizarre. After all, if a primitive turns into an object when it needs to do something useful, why not just stay an object always? The answer has to do with memory consumption.
If you have a question about this or any other topic, the easiest thing is to drop by our forums where a bunch of the friendliest people you'll ever run into will be happy to help you out!
THE KIRUPA NEWSLETTER
Get cool tips, tricks, selfies, and more...personally hand-delivered to your inbox!
( View past issues for an idea of what you've been missing out on all this time! )