Boxing Wrappers
These object wrappers serve a very important purpose. Primitive values don’t have properties or methods, so to access .length
or .toString()
you need an object wrapper around the value. Thankfully, JS will automatically box (aka wrap) the primitive value to fulfill such accesses.
var a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
So, if you’re going to be accessing these properties/methods on your string values regularly, like a i < a.length
condition in a for
loop for instance, it might seem to make sense to just have the object form of the value from the start, so the JS engine doesn’t need to implicitly create it for you.
But it turns out that’s a bad idea. Browsers long ago performance-optimized the common cases like .length
, which means your program will actually go slower if you try to “preoptimize” by directly using the object form (which isn’t on the optimized path).
In general, there’s basically no reason to use the object form directly. It’s better to just let the boxing happen implicitly where necessary. In other words, never do things like new String("abc")
, new Number(42)
, etc — always prefer using the literal primitive values "abc"
and 42
.
Object Wrapper Gotchas
There are some gotchas with using the object wrappers directly that you should be aware of if you do choose to ever use them.
For example, consider Boolean
wrapped values:
var a = new Boolean( false );
if (!a) {
console.log( "Oops" ); // never runs
}
The problem is that you’ve created an object wrapper around the false
value, but objects themselves are “truthy” (see Chapter 4), so using the object behaves oppositely to using the underlying false
value itself, which is quite contrary to normal expectation.
If you want to manually box a primitive value, you can use the Object(..)
function (no new
keyword):
var a = "abc";
var b = new String( a );
var c = Object( a );
typeof a; // "string"
typeof b; // "object"
typeof c; // "object"
b instanceof String; // true
c instanceof String; // true
Object.prototype.toString.call( b ); // "[object String]"
Object.prototype.toString.call( c ); // "[object String]"
Again, using the boxed object wrapper directly (like b
and c
above) is usually discouraged, but there may be some rare occasions you’ll run into where they may be useful.