Why should you not use Number as a constructor? [duplicate]

一个人想着一个人 提交于 2019-11-27 04:04:55

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
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"

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.

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));

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.

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.)

This answer / summry was extracted from the question where it does not belong.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!