来自 es-discuss@mozilla.org 邮件列表的 Brendan Eich 的快速回复:
考虑 Perl:
$ perl -e 'print 0 == "true";'
1
好的,理由很糟糕——但我在 1995 年 5 月在 AWK、Perl 4、Python 1.2 (IIRC)、TCL 的阴影下创建了 JS。
考虑到我应该比 Perl 更关注 AWK
$ awk 'END {print(0 == "0")}'
1D
$ awk 'END {print(0 == "")}'
0D
在某些方面,JS 的运算符通过转换为 NaN来==
拆分 Perl(非数字字符串,例如"true"
转换为0
)和 AWK(仅"0"
转换为)之间的差异。0
这样,至少,我们有
js> 0 == ""
true
js> 0 == "true"
false
但完整的事实并不是我在仔细模仿其他语言。相反,一些致力于在类似 PHP 的服务器 (LiveWire) 中嵌入 JS(然后是“Mocha”)的 Netscaper 希望进行草率的转换,因此程序员可以匹配 HTTP 标头字符串(服务器端)或 HTML 表单字段(客户端),例如, 404等,没有程序员的明确强制。
但那是 90 年代,我急得要命,这些前 Borland Netscapers 坚持不懈。所以,正如我去年在 Strange Loop所说的,“我是个白痴!我给了他们想要的东西!”
隐式转换是我对 JS 仓促设计的最大遗憾,没有之一。甚至包括“与”!
有谁知道选择不将任何值与 == 运算符中的布尔值相比转换为布尔值的确切原因?
一般的想法是较窄的类型应该加宽。因此,true == 1
接下来将 boolean 投影{false, true}
到 上{0, 1}
,就像在 C++ 中一样。
但是为什么不扩大true
到字符串,因为您示例中的另一个操作数是"true"
?好问题。如果操作数是数字或布尔值,则将字符串作为数字进行比较的偏见源于 HTTP 标头和数字字符串 HTML 表单字段用例。再次,不是很好的理由,但这就是JS“工作”的方式:-|。
您可以在 ECMA-262 Edition 5.1 规范中看到这一点,11.9.3 The Abstract Equality Comparison Algorithm,第 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) 是 Boolean,返回比较结果 ToNumber(x) == y。
7. 如果 Type(y) 为 Boolean,则返回比较结果 x == ToNumber(y)。
这一切都在一个大的“else 子句中,其中Type(x)
和Type(y)
forx == y
不一样。
抱歉,这里没有智慧的珍珠(原文如此)。除了隐式转换,==
不要!=
将操作数直接加宽(没有中间转换)到可以容纳其他操作数而不会丢失数据的最窄宽度。这种将字符串缩小为数字的做法只是一个烂摊子。
如果我们修复了这个问题,我们仍然有:
0 == "0"
1 == "1"
true != "1"
false != "0"
但我们也会有你的例子想要的:
true == "true"
false != ""
根据我将数字优先于字符串转换的偏好称为拙劣,我们不会有true == "1"
or false == "0"
,因为它会从字符串缩小到数字。确实,缩小不会丢失任何位,并且可以扩大0
到"0"
和1
回到"1"
,但我的意思是说明从 == 的隐式转换规范中删除所有数字上的字符串偏差会做什么。
这样的更改会破坏网络上的大量代码吗?我敢打赌它会。
有些人认为,除了任何隐式转换之外,还有一个使用===
and的原因!==
(因为他们从不转换),并且完全避开==
and !=
。其他人不同意(尤其是在测试时x == null
,一种单操作员方式test x === null || x === undefined
)。
由于网络在很大程度上是兼容的,直到非常旧的形式消亡,我们被 and 困住了==
,!=
所以我说学习草率的相等运算符做什么是值得的。这样做后,在我看来,他们可能会在获胜的地方使用它们:当您知道操作数是相同类型时,例如
typeof x == "function"
, ETC。
x == null
否则,使用===
and !==
。
如果操作数是数字或布尔值,则将字符串作为数字进行比较的偏见源于 HTTP 标头和数字字符串 HTML 表单字段用例。再次,不是很好的理由,但这就是JS“工作”的方式:-|。
还有一点需要注意:如果任何非数字、非空的字符串到数字的隐式转换尝试抛出一个例外。
这是 JS 设计位中另一个依赖于路径的偏差:在 JS1 或任何 ECMA-262 标准中直到 ES3 都没有 try/catch。
缺少异常处理也意味着undefined
缺少obj.foo
属性 getobj
没有此类属性。这仍然在咬人,可能与隐式转换咬人一样多或更多==
。它也是 web JS 获胜的“对象检测”模式的基础,它完全击败了我见过的所有其他版本控制方案,尤其是基于显式编号和选择加入的先验方案。
要是我花时间为对象检测添加一个存在运算符就好了,这样就可以写了
function emulateRequestAnimationFrame(...) {...}
if (!window.requestAnimationFrame?)
window.requestAnimationFrame = emulateRequestAnimationFrame;
IOW,如果我window.noSuchProperty
投掷但window.noSuchProperty?
评估为真或false
(细节仍然待定,请参阅“快速失败的对象解构”线程复兴,Nil 想法)。