为啥 JavaScript 在连接时优先强制转换为字符串,而在比较时优先转换为数字?
Posted
技术标签:
【中文标题】为啥 JavaScript 在连接时优先强制转换为字符串,而在比较时优先转换为数字?【英文标题】:Why does JavaScript preferentially coerce to strings when concatenating but numbers when comparing?为什么 JavaScript 在连接时优先强制转换为字符串,而在比较时优先转换为数字? 【发布时间】:2019-01-10 16:21:12 【问题描述】:为什么 javascript 在使用连接 +
运算符时优先将操作数强制转换为字符串,但在执行 ==
相等检查时优先将操作数强制转换为数字?
'1' + 1
被强制转换为 '1' + '1'
并返回 '11'
。
'1' == 1
被强制转换为 1 === 1
并返回 true
。
在比较情况下,它们被强制转换为数字,而不是字符串。请参阅以下来源:
1) Douglas Crockford's Encyclopedia
== 运算符产生与此函数相同的结果:
function coercing_equal(left, right)
if (left === right)
return true ;
if (left === null)
return right === undefined;
if (right === null)
return left === undefined;
if (typeof left === 'number' && typeof right === 'string')
return left === +right;
if (typeof left === 'string' && typeof right === 'number')
return +left === right;
if (typeof left === 'boolean')
return coercing_equal(+left, right);
if (typeof right === 'boolean')
return coercing_equal(left, +right);
if
(typeof left === 'object' &&
(
left.constructor === Number ||
left.constructor === String ||
left.constructor === Boolean
) &&
(typeof right === 'string' || typeof right === 'number')
)
return coercing_equal(left.valueOf(), right);
if (
(typeof left === 'string' || typeof left === 'number') &&
typeof right === 'object' &&
(
right.constructor === Number ||
right.constructor === String ||
right.constructor === Boolean
)
)
return coercing_equal(left, right.valueOf());
return false ;
2) MDN
当比较中涉及到类型转换(即非严格比较)时,JavaScript 将 String、Number、Boolean 或 Object 操作数的类型转换如下:
比较数字和字符串时,字符串会转换为数字值。 JavaScript 尝试将字符串数字文字转换为数字类型值。首先,数学值是从字符串数字文字派生的。接下来,将此值四舍五入到最接近的数字类型值。
如果其中一个操作数是布尔值,则布尔操作数如果为真则转换为 1,如果为假则转换为 +0。
如果将对象与数字或字符串进行比较,JavaScript 会尝试返回该对象的默认值。运算符尝试使用对象的 valueOf 和 toString 方法将对象转换为原始值、字符串或数字值。如果转换对象的尝试失败,则会生成运行时错误。
请注意,当且仅当其比较对象是基元时,对象才会转换为基元。如果两个操作数都是对象,则将它们作为对象进行比较,并且只有当两个操作数都引用同一个对象时,相等性测试才为真。
这有什么理由吗,还是只是“因为 JavaScript”的另一种情况?就我目前的理解而言,很难记住。
【问题讨论】:
阅读规范。'1' + 1
== ('1').toString() + (1).toString()
你怎么知道'1' == 1
被强制转换为1 === 1
而不是'1' === '1'
?
@jhpratt “== 中缀运算符”部分伪代码(第 4 和第 5 个 if 语句)。
我不会说这只是“因为 javascript”。有一些很好的理由表明我们可能更喜欢一种转换而不是另一种。对于==
,将两者都转换为数字具有很好的特性。例如,比较任意两个虚假值(NaN
除外)将返回 true,例如 "" == 0
。同样,在+
的情况下,由于许多字符串不是数字,我宁愿让"foo" + 1
成为"foo1"
而不是NaN
(如果我们将两者都转换为数字)。
【参考方案1】:
为什么你认为只有一个原因? 我相信可能有不同的方面:
html 数据不是输入的——它都是字符串。 HTTP 也是如此。因此,如果您尝试这样做,可能需要进行大量转换
element.getAttribute('maxlength')> str.length
所以我们最好只处理字符串/数字混合不是大写的事实(至少在开始使用 EcmaScript 时)
尝试对“+”和“>”运算符使用相同的方法会产生更多的“WTF?”。假设我们尝试在任何地方使用“toString 方法”然后2> '11'
。另一方面,对于“toNumber 方法无处不在”,我们会在字符串连接结果中看到NaN
,这比我们想要的要频繁得多。
是的,它看起来很混乱。但这更多是因为“+”作为运算符“add”和操作“concatenate”同时存在的模糊目标。然后你应该习惯自动操作。
【讨论】:
以上是关于为啥 JavaScript 在连接时优先强制转换为字符串,而在比较时优先转换为数字?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 iOS 应用程序中的变量或强制转换为空? [复制]