32

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.

Community
  • 1
  • 1

6 Answers6

40

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
}

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
VLAZ
  • 26,331
  • 9
  • 49
  • 67
Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
  • 9
    I don't think the use of `Number` as a constructor should be discouraged. The developer just needs to know that a constructor always returns an object, and how to work with that, not against it. –  Jul 23 '13 at 15:50
  • «they test for identity, not equality» this is nuts, there's a reasonable explanation why `==` and `===` shouldn't test equality? There's a different operator that tests equality in JS? – Sdlion Jun 29 '19 at 00:35
  • 1
    @Sdlion No, all of the equality and inequality operators only compare references for objects. Primitive types like number, string, and boolean are compared by value though, since reference equality wouldn't have any meaning or use. – Matthew Crumley Jul 01 '19 at 20:17
  • 1
    @Sdlion As to the reasoning, I can only guess, but the two things that come to mind are, that's how Java works, and complexities about what exactly equality would mean for objects. For example, if two objects had the same properties and values, but different prototypes. Or the same properties, but different enumeration orders. There would also need to be decisions about whether it should be a deep or shallow comparison, and what to do about cycles. Personally, I haven't found the way it works to be a problem in most cases, as long as you avoid the primitive wrappers. – Matthew Crumley Jul 01 '19 at 20:23
20
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
  • 137,716
  • 26
  • 137
  • 190
6

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
  • 54,908
  • 28
  • 127
  • 156
6

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
  • 20,015
  • 9
  • 55
  • 79
6

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
  • 3,391
  • 1
  • 18
  • 9
1

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.

Community
  • 1
  • 1
cat
  • 3,888
  • 5
  • 32
  • 61