JavaScript Primitive Wrapper Types

原创转载请注明出处:http://agilestyle.iteye.com/blog/2341689

 

Primitive Wrapper Types

Perhaps one of the most confusing parts of JavaScript is the concept of primitive wrapper types. There are three primitive wrapper types (String, Number, and Boolean). These special reference types exist to make working with primitive values as easy as working with objects. (It would be very confusing if you had to use a different syntax or switch to a procedural style just to get a substring of text.)

The primitive wrapper types are reference types that are automatically created behind the scenes whenever strings, numbers, or Booleans are read. For example, in the first line of this listing, a primitive string value is assigned to name. The second line treats name like an object and calls charAt(0) using dot notation.

var name = "Nicholas";
var firstChar = name.charAt(0);
console.log(firstChar);			// "N"

 

This is what happens behind the scenes:

// what the JavaScript engine does
var name = "Nicholas";
var temp = new String(name);
var firstChar = temp.charAt(0);
console.log(firstChar);			// "N"

 

Because the second line uses a string (a primitive) like an object, the JavaScript engine creates an instance of String so that charAt(0) will work. The String object exists only for one statement before it’s destroyed (a process called autoboxing). To test this out, try adding a property to a string as if it were a regular object:

var name = "Nicholas";
name.last = "Zakas";
console.log(name.last);			// undefined

 

This code attempts to add the property last to the string name. The code itself is just fine except that the property disappears. What happened? When working with regular objects, you can add properties at any time and they stay until you manually remove them. With primitive wrapper types, properties seem to disappear because the object on which the property was assigned is destroyed immediately afterward.

Here’s what’s actually happening in the JavaScript engine: 

// what the JavaScript engine does
var name = "Nicholas";
var temp = new String(name);
temp.last = "Zakas";
temp = null;					// temporary object destroyed
var temp = new String(name);
console.log(temp.last);			// undefined
temp = null;

 

Instead of assigning a new property to a string, the code actually creates a new property on a temporary object that is then destroyed. When you try to access that property later, a different object is temporarily created and the new property doesn’t exist there. Although reference values are created automatically for primitive values, when instanceof checks for these types of values the result is false:

var name = "Nicholas";
var count = 10;
var found = false;
console.log(name instanceof String);	// false
console.log(count instanceof Number);	// false
console.log(found instanceof Boolean);	// false

 

The instanceof operator returns false because a temporary object is created only when a value is read. Because instanceof doesn’t actually read anything, no temporary objects are created, and it tells us the values aren’t instances of primitive wrapper types. You can create primitive wrapper types manually, but there are certain side effects:

var name = new String("Nicholas");
var count = new Number(10);
var found = new Boolean(false);
console.log(typeof name);		// "object"
console.log(typeof count);		// "object"
console.log(typeof found);		// "object"

 

As you can see, creating an instance of the primitive wrapper type just creates another object, which means that typeof can’t identify the type of data you intend to store.

In addition, you can’t use String, Number, and Boolean objects as you would primitive values.

For example, the following code uses a Boolean object. The Boolean object is false, yet console.log(“Found”) still executes because an object is always considered true inside a conditional statement. It doesn’t matter that the object represents false; it’s an object, so it evaluates to true.

var found = new Boolean(false);
if (found) {
	console.log("Found");		// this executes
}

 

Manually instantiating primitive wrappers can also be confusing in other ways, so unless you find a special case where it makes sense to do so, you should avoid it. Most of the time, using primitive wrapper objects instead of primitives only leads to errors.

 

Conclusion

To make primitives seem more like references, JavaScript has three primitive wrapper types: String, Number, and Boolean. JavaScript creates these objects behind the scenes so that you can treat primitives like regular objects, but the temporary objects are destroyed as soon as the statement using them is complete. Although you can create your own instances of primitive wrappers, it’s best not to do that because it can be confusing.

 

Reference

Leanpub.Principles.of.Object-Oriented.Programming.in.JavaScript.Jun.2014

 

猜你喜欢

转载自agilestyle.iteye.com/blog/2341689