views:

711

answers:

5

I entered this statement in JSLint:

var number = new Number(3);

And received the following message:

Do not use Number as a constructor.

Why is that? The statement is creating a number object, not a primitive value, so I don't see why using new is a problem.

EDIT: Thanks for all the responses. They've got me thinking further, so I posted a follow-up question here.

UPDATE: Thanks again for all the responses! They've been very helpful. I guess to sum up, in JavaScript, an Object type is not equal to another Object type, even when they have the exact same value, unless they are both the EXACT SAME object.

In other words, in Matthew's example below, n1 == n2 is false because you are comparing two REFERENCES to two SEPARATE objects, but n1 == n1 is true because you are comparing references to the EXACT SAME object.

So, while I now understand why using Number as a constructor can cause problems, I found you can use the valueOf property when comparing Number objects.

In other words, n1.valueOf == n2.valueOf is true! (This is because you're comparing the return values of the valueOf FUNCTION, not the REFERENCES to the objects themselves.)

+4  A: 
var number = new Number(3);
alert(typeof number); // gives "object"

Making the variable number have a type of Object is probably not the most desired outcome. Whereas:

var number = Number(3);
alert(typeof number); // gives "number"
Ates Goral
+4  A: 

Unfortunately, the JSLint docs don't go into any further detail than "does not expect to see", so we're left to guess. My own suspicion is that this is to make type-checking easier:

assert(typeof 3             === "number");
assert(typeof new Number(3) === "object");

If you mix the two in your code, your type checks become more complex:

if (typeof foo === "number" || foo instanceof Number) { … }

However, JSLint also takes issue with the Object and Array constructors, which do not make this distinction, so it may simply be the author's coding-style preference:

assert(typeof []           === "object");
assert(typeof new Array()  === "object");
assert(typeof {}           === "object");
assert(typeof new Object() === "object");

Edit: Steven's answer raises an excellent point — the non-typecasting equality operator (===). Number objects and number primitives will never be considered equal by this operator, even if their values are the same:

assert(3 !== new Number(3));
Ben Blank
+4  A: 

new Number() does not return the same object as a number literal. This means that using new Number() breaks ===, which is the best way to check for exact equality in Javascript.

>>> 3 == 1 + 2
true
>>> 3 === 1 + 2
true
>>> new Number(3) == 1 + 2
true
>>> new Number(3) === 1 + 2
false

You can find the rationale for JSLint's behavior in the author's book, JavaScript: The Good Parts, in Appendix C.

Steven Huwig
I've got that book on my holiday gift list!
+14  A: 

In addition to breaking === and typeof returning "object", using the Number constructor also changes the way the value is used in boolean contexts. Since "new Number(0)" is an object, not a literal value, it evaluates as "true" because it is not null. So for example:

var n1 = 0;
var n2 = new Number(0);

n1 == n2  // true
n1 === n2 // false
if (n1) {
    // Doesn't execute
}
if (n2) {
    // Does execute, because n2 is an object that is not null
}

Edit: Even worse than breaking === between number literals and Number objects, == doesn't even work between two Number objects (at least not in the intuitive way -- they test for identity, not equality).

var n1 = new Number(3);
var n2 = new Number(3);

alert(n1 == n2); // false
alert(n1 === n2); // false
Matthew Crumley
+3  A: 

It's slower, and requires more memory. The runtime can treat immutable literals as immutable literals. That means that when it encounters 3 somewhere in code, it can optimize that into a shared object. When you use the Number constructor, new memory is allocated for each instance.

pottedmeat