当一个是布尔值时,为什么JavaScript将原始值转换为==运算符比较中的数字的原理?

Ray*_*Ray 7 javascript

我知道规则:

如果两个操作数的类型不同,则JavaScript转换操作数,然后应用严格比较.如果操作数是数字或布尔值,操作数将尽可能转换为数字; 否则,如果任一操作数是字符串,则另一个操作数将转换为字符串(如果可能).

因此,if("true")传递但if("true" == true)失败,因为它像句柄一样 if(NaN == 1).

当一个值是布尔值时,我想知道这背后的理性是什么.在其他弱类型语言(如php)中,这是以不同的方式处理 - 如果一个值是布尔值,另一个值将转换为布尔值进行比较(而不是像javascript那样将数字转换为数字).

我假设这个选择是==经过慎重考虑的.任何人都可以提供理由,为什么这是选择的功能?是否有一个常见的用例,这是选择解决?我打赌这不仅仅是一个错误.

Ray*_*Ray 8

来自es-discuss@mozilla.org邮件列表的Brendan Eich的响应速度非常快:

考虑Perl:

$ perl -e 'print 0 == "true";'
1
Run Code Online (Sandbox Code Playgroud)

好的,理由很差 - 但我在1995年5月,在AWK,Perl 4,Python 1.2(IIRC),TCL的阴影下创建了JS.

鉴于,我应该更多地关注AWK而不是Perl

$ awk 'END {print(0 == "0")}'
1D
$ awk 'END {print(0 == "")}'
0D
Run Code Online (Sandbox Code Playgroud)

在某些方面,JS的==运算符通过转换为NaN 来区分Perl(其中非数字字符串,如"true"convert to 0)和AWK(仅"0"转换为0)之间的差异.这样,至少,我们有

js> 0 == ""
true
js> 0 == "true"
false
Run Code Online (Sandbox Code Playgroud)

但完全的事实不是我在小心翼翼地模仿其他语言.相反,一些Netscapers努力将JS(当时的"Mocha")嵌入到类似PHP的服务器(LiveWire)中需要进行简单的转换,因此程序员可以匹配HTTP头字符串(服务器端)或HTML表单字段(客户端),例如, 404等等,没有程序员的明确强制.

但那是90年代,我匆匆忙忙,这些前Borland Netscapers坚持不懈.所以,就像我去年Strange Loop所说的那样,"我是个白痴!我给了他们想要的东西!"

隐藏的转换是我在JS匆忙设计中最大的遗憾,没有.甚至包括'带'!

有没有人知道选择的确切原因是没有转换为boolean任何值与使用==运算符的布尔值进行比较?

一般的想法是狭窄的类型应该扩大.因此,true == 1通过将boolean投影{false, true}{0, 1}C++ 上,如下所示.

但是为什么不加宽true到字符串,因为你的例子中的另一个操作数是"true"?好问题.如果操作数是数字或布尔值,则将字符串作为数字进行比较的偏见源于HTTP标头和数字字符串HTML表单字段用例.不是很好的理由,但这就是JS"工作"的方式: - |.

您可以在ECMA-262 Edition 5.1规范11.9.3抽象等效比较算法,步骤6和7(根据步骤4和5阅读)中看到这一点:

4.如果Type(x)为Number且Type(y)为String,则返回比较结果x == ToNumber(y).
5.如果Type(x)是String而Type(y)是Number,则返回比较结果ToNumber(x)== y.
6.如果Type(x)是布尔值,则返回比较结果ToNumber(x)== y.
7.如果Type(y)是布尔值,则返回比较结果x == ToNumber(y).

这一切都是在一个大的"else where子句中Type(x)Type(y)x == y是不一样的.

对不起,这里没有明珠(原文如此).除了隐式转换,==并且!=不直接加宽操作数(无中间转换),以能够保持而不会丢失数据的另一个操作数的最窄宽度.这个缩小的字符串数字只是一个拙劣.

如果我们修复了这个问题,我们仍然会:

0 == "0"
1 == "1"
true != "1"
false != "0"
Run Code Online (Sandbox Code Playgroud)

但是我们也会有你想要的例子:

true == "true"
false != ""
Run Code Online (Sandbox Code Playgroud)

根据我的号码对字符串转换的数字偏好,我们不会有true == "1"false == "0"因为从字符串到数字变窄.确实,缩小不会丢失任何位,并且可以0扩展回到"0"1返回"1",但我的意思是说明从==的隐式转换规范中删除所有字符串数偏移量.

这样的改变会破坏网络上的很多代码吗?我敢打赌会有大笔款项.

有的借此误事,引擎盖下的任何隐式转换的顶部,另一个理由使用===!==总是(因为他们从来没有转换),并完全顺==!=.其他人不同意(特别是在测试时x == null,采用单操作员方式test x === null || x === undefined).

由于网络的增长主要是-兼容直到很老的形式死光了,我们坚持用==!=,所以我说是值得学习的东西马虎平等运营商做.完成后,在我看来,人们可以在胜利的地方使用它们:当你知道操作数是同一类型时,例如

typeof x == "function"
x == null

否则,使用===!==.

如果操作数是数字或布尔值,则将字符串作为数字进行比较的偏见源于HTTP标头和数字字符串HTML表单字段用例.不是很好的理由,但这就是JS"工作"的方式: - |.

还有一点需要注意:可以认为,如果任何非数字,非空的字符串到数字的隐式转换尝试抛出,则从字符串到数字的缩小将是正常的(如在大多数情况下有用,并且不是不安全的)例外.

这是JS设计中另一个与路径相关的偏差:在JS1中没有try/catch,或者在ES3之前没有任何ECMA-262标准.

缺乏异常处理也意味着undefined缺少obj.foo财产获得obj没有这种财产的地方.这仍然是令人讨厌的,可能与隐含的转换一样多或多==.它也是web JS获胜的"对象检测"模式的基础,它与我见过的所有其他版本控制方案相当,特别是基于显式编号和选择加入的先验版本.

如果我只是花时间为对象检测添加一个存在运算符,那么就可以写了

function emulateRequestAnimationFrame(...) {...}
if (!window.requestAnimationFrame?)
  window.requestAnimationFrame = emulateRequestAnimationFrame;
Run Code Online (Sandbox Code Playgroud)

IOW,如果我只是window.noSuchProperty投掷但是window.noSuchProperty?评价为真或者false(细节仍然是TBD,请参阅"失败快速对象解构"线程复兴,Nil的想法).

  • 凉.我想格式化帖子以将代码格式转换为引号,但我不确定第二个是否来自你或Brendan ...可以请尽可能好地格式化帖子以明确他写的内容,什么是你的问题(他可能引用了什么)等等? (2认同)