为啥 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 应用程序中的变量或强制转换为空? [复制]

在 Objective-C 中,为啥在分配给指定类型的变量时需要强制转换?

泛型:强制转换和值类型,为啥这是非法的?

SV强制类型转换和常数

javascript 怎么将float强制转换为int类型

为啥 + [] 在 Javascript 中返回 0? [复制]