为啥不应该使用 Number 作为构造函数? [复制]

Posted

技术标签:

【中文标题】为啥不应该使用 Number 作为构造函数? [复制]【英文标题】:Why should you not use Number as a constructor? [duplicate]为什么不应该使用 Number 作为构造函数? [复制] 【发布时间】:2010-09-27 00:30:30 【问题描述】:

我在 JSLint 中输入了这条语句:

var number = new Number(3);

并收到以下消息:

不要使用 Number 作为构造函数。

这是为什么呢?该语句是创建一个数字对象,而不是原始值,所以我不明白为什么使用new 是一个问题。

编辑:感谢所有回复。他们让我进一步思考,所以我发布了一个后续问题here。

【问题讨论】:

你能把后续问题放在一个新问题中以保持正确吗? 【参考方案1】:

除了打破 === 和 typeof 返回“object”之外,使用 Number 构造函数还改变了值在布尔上下文中的使用方式。由于“new Number(0)”是一个对象,而不是文字值,因此它的计算结果为“true”,因为它不为空。比如:

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

比在数字文字和数字对象之间破坏 === 更糟糕的是,== 甚至在两个数字对象之间都不起作用(至少不是以直观的方式——它们测试的是同一性,而不是相等性)。

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

alert(n1 == n2); // false
alert(n1 === n2); // false

【讨论】:

我认为不应该鼓励使用Number 作为构造函数。开发人员只需要知道构造函数总是返回一个对象,以及如何使用它,而不是反对它。 «他们测试身份,而不是平等»这太疯狂了,有一个合理的解释为什么===== 不应该测试平等?有一个不同的运算符来测试 JS 中的相等性吗? @Sdlion 不,所有的相等和不等运算符只比较对象的引用。但是像数字、字符串和布尔值这样的原始类型是按值比较的,因为引用相等没有任何意义或用途。 @Sdlion 至于推理,我只能猜测,但我想到的两件事是,这就是 Java 的工作原理,以及关于对象的确切含义的复杂性。例如,如果两个对象具有相同的属性和值,但原型不同。或者属性相同,但枚举顺序不同。还需要决定是否应该进行深度比较或浅表比较,以及如何处理周期。就个人而言,在大多数情况下,只要您避免使用原始包装器,我还没有发现它的工作方式会成为问题。【参考方案2】:

javascript 中,一个 Object 类型不等于另一个 Object 类型,即使它们具有完全相同的值,除非它们都是 EXACT SAME 对象。

换句话说,在下面 Matthew 的示例中,n1 == n2 为 false,因为您将两个 REFERENCES 与两个 SEPARATE 对象进行比较,但 n1 == n1 为 true,因为您将引用与 EXACT SAME 对象进行比较。

所以,虽然我现在明白了为什么使用 Number 作为构造函数会导致问题,但我发现在比较 Number 对象时可以使用 valueOf 属性。

换句话说,n1.valueOf == n2.valueOf 是真的! (这是因为您正在比较 valueOf FUNCTION 的返回值,而不是 REFERENCES 与对象本身。)

这个答案/摘要是从它不属于的问题中提取的。

【讨论】:

【参考方案3】:

速度较慢,需要更多内存。运行时可以将不可变文字视为不可变文字。这意味着当它在代码中的某处遇到3 时,它可以将其优化为共享对象。当您使用Number 构造函数时,会为每个实例分配新内存。

【讨论】:

【参考方案4】:

不幸的是,JSLint docs 没有比“不希望看到”更进一步的细节,所以我们只能猜测。我自己的怀疑是,这是为了使类型检查更容易:

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

如果您在代码中混合使用这两者,您的类型检查会变得更加复杂:

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

然而,JSLint 也对 Object 和 Array 构造函数提出了质疑,它们没有进行这种区分,所以这可能只是作者的编码风格偏好:

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

编辑: Steven 的回答提出了一个很好的观点——非类型转换相等运算符 (===)。此运算符永远不会认为数字对象和数字基元相等,即使它们的值相同:

assert(3 !== new Number(3));

【讨论】:

【参考方案5】:

new Number() 不会返回与数字文字相同的对象。这意味着使用 new Number() 会中断 ===,这是在 Javascript 中检查完全相等的最佳方法。

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

您可以在作者的著作JavaScript: The Good Parts 的附录 C 中找到 JSLint 行为的基本原理。

【讨论】:

我的节日礼物清单上有那本书!【参考方案6】:
var number = new Number(3);
alert(typeof number); // gives "object"

使变量number 具有Object 的类型可能不是最理想的结果。鉴于:

var number = Number(3);
alert(typeof number); // gives "number"

【讨论】:

以上是关于为啥不应该使用 Number 作为构造函数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥不应该在Angular中组件的构造函数中进行数据初始化?

为啥在malloc中不调用构造函数? [复制]

为啥在malloc中不调用构造函数? [复制]

C++:调用无参数的构造函数为啥不加括号

为啥我们使用 const 和 reference 作为参数来复制构造函数?

为啥这里的 String 构造函数应该被保护而不是私有?