What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?
codemash 2012的"wat"讨论基本上指出了Ruby和JavaScript的一些奇怪的特性。
我在http://jsfiddle.net/fe479/9/上对结果进行了jsfiddle处理。
下面列出了特定于javascript(我不知道Ruby)的行为。
我在jsFiddle中发现我的一些结果与视频中的结果不一致,我不知道为什么。不过,我很想知道在每种情况下,javascript是如何处理幕后工作的。
1 2 3 4 | Empty Array + Empty Array [] + [] result: <Empty String> |
我很好奇在与JavaScript中的数组一起使用时,
1 2 3 4 | Empty Array + Object [] + {} result: [Object] |
这与视频的结果相匹配。这是怎么回事?为什么这是一个物体。
1 2 3 4 | Object + Empty Array {} + [] result [Object] |
这与视频不匹配。视频显示结果是0,而我得到了[对象]。
1 2 3 4 | Object + Object {} + {} result: [Object][Object] |
这也与视频不匹配,输出变量如何产生两个对象?也许我的琴错了。
1 2 3 | Array(16).join("wat" - 1) result: NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN |
做wat+1会导致
我怀疑这只是简单的行为,尝试从一个字符串中减去一个数字会得到NaN。
以下是您看到的(和应该看到的)结果的解释列表。我使用的参考资料来自ECMA-262标准。
当使用加法运算符时,左操作数和右操作数都首先转换为原语(§11.6.1)。根据§9.1,将对象(在本例中是数组)转换为原语将返回其默认值,对于使用有效
与
这里的
与前一种情况类似,第一个
If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber is NaN.
根据第15.4.1.1条和第15.4.2.2条,
If either operand is NaN, the result is NaN.
因此,对
If m is NaN, return the String
"NaN" .
在§15.4.4.5的第10步之后,我们得到15个重复的
至于为什么在
这与其说是回答,不如说是评论,但出于某种原因,我不能对你的问题发表评论。我想更正您的JSfiddle代码。然而,我把这个贴在黑客新闻上,有人建议我把它转寄到这里。
JSfiddle代码中的问题是
基本的想法是简单的javascript允许这两种形式:
1 2 3 4 5 6 7 | if (u) v; if (x) { y; z; } |
为此,对开口撑架进行了两种解释:1。不需要和2。它可以出现在任何地方。
这是个错误的举动。真正的代码没有出现在任何地方的中间的左大括号,而真正的代码在使用第一种形式而不是第二种形式时也往往更脆弱。(大约每隔一个月,在我上一份工作中,当他们对我的代码的修改不起作用时,我会接到同事的电话,问题是他们在"if"中添加了一行,而没有添加大括号。我最终还是养成了这样的习惯:即使你只写一行,也总是需要大括号。)
幸运的是,在许多情况下,eval()将复制javascript的完整功能。jsFiddle代码应为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function out(code) { function format(x) { return typeof x ==="string" ? JSON.stringify(x) : x; } document.writeln('>>> ' + code); document.writeln(format(eval(code))); } document.writeln("[cc lang="javascript"]"); out('[] + []'); out('[] + {}'); out('{} + []'); out('{} + {}'); out('Array(16).join("wat" + 1)'); out('Array(16).join("wat - 1")'); out('Array(16).join("wat" - 1) +" Batman!"'); document.writeln(" |
"";< /代码>
[这也是我多年来第一次写document.writeln,我觉得写任何涉及document.writeln()和eval()的东西都有点脏]
在第二ventero"的解决方案。如果你想,你可以去享受到零售为两个
第一步:(§9.1)convert operands primitives(两个都是
对于约会,步骤1和2是swapped。你可以要守的转换为follows行为:
1 2 3 4 5 6 7 8 9 10 | var obj = { valueOf: function () { console.log("valueOf"); return {}; // not a primitive }, toString: function () { console.log("toString"); return {}; // not a primitive } } |
(
1 2 3 4 | > Number(obj) valueOf toString TypeError: Cannot convert object to primitive value |
第二步(§11.6.1):如果一个字符串的operands冰,冰也其他操作数转换和结果两个字符串连接两市的冰产生的字符串。否则,两个都是operands转换结果数和冰淇淋生产增他们的城市。
更详细的转换过程的解释:"什么是{ } { } +在JavaScript的?"
我们两个可以参考的规范和《这是伟大的和最准确的,但必须是explained用例也可以在一个更comprehensible方式与下面的陈述:
-
+ 和- 经营者的工作只与原始值。更具体来说+ (ADD)厂用它的字符串或数字,和+ (一元)和- (subtraction鸭厂只与一元)数。 - 全天然,函数或运营商的期望值作为原始参数,将这两个参数,第一convert desired原始类型。它是好的或与
valueOf toString ,这是在任何可用的对象。这是原因为什么这样的函数或运营商不要把错误的时候invoked在线数据。
所以我们可以说,:
-
[] + [] 冰一样的String([]) + String([]) AA AA'' + '' 这是相同的。首先,在上述+ (ADD)的冰也有效数,但有没有有效的阵列个数表示在母猪添加JavaScript字符串,而不是用冰。 -
[] + {} 冰一样的String([]) + String({}) AA AA'' + '[object Object]' 这是相同的 -
{} + [] 。这一个有趣的deserves解释(见ventero答案)。在那卷曲的牙套,个案处理,是不是作为一个对象,但作为一个空座了,所以我会为+[] 是相同的。一元+ 厂只与数,所以tries的实施得到了[] 一号。第一,它triesvalueOf 的情况下返回相同的对象的数组,然后我它tries度假村:最后一个toString 转换结果的两个数。我们可以为它写+Number(String([])) 这是相同的+Number('') AA AA+0 这是相同的。 -
Array(16).join("wat" - 1) subtraction- 厂只与数,所以它的一样:Array(16).join(Number("wat") - 1) AA,AA"wat" 不能转换的两个有效数字。我们收到NaN ,和任何NaN 算术操作的结果与NaN ,所以我们有:Array(16).join(NaN) 。
支持之前分享的东西。
这种行为的根本原因部分是由于JavaScript的弱类型性。例如,表达式1+"2"不明确,因为基于操作数类型(int、string)和(int int int)有两种可能的解释:
- 用户打算连接两个字符串,结果:"12"
- 用户打算添加两个数字,结果:3
因此,随着输入类型的变化,输出可能性增加。
加法算法
javascript原语有string、number、null、undefined和boolean(ES6中很快就会出现符号)。任何其他值都是一个对象(例如数组、函数和对象)。将对象转换为基元值的强制过程如下所述:
如果在调用object.valueof()时返回原语值,则返回该值,否则继续
如果在调用object.toString()时返回原语值,则返回该值,否则继续
引发类型错误
注意:对于日期值,顺序是在valueof之前调用ToString。
如果任何操作数值是字符串,则执行字符串串联
否则,将两个操作数转换为它们的数值,然后添加这些值
了解javascript中各种类型的强制值有助于使混淆的输出更加清晰。见下表
1 2 3 4 5 6 7 8 9 10 11 | +-----------------+-------------------+---------------+ | Primitive Value | String value | Numeric value | +-----------------+-------------------+---------------+ | null |"null" | 0 | | undefined |"undefined" | NaN | | true |"true" | 1 | | false |"false" | 0 | | 123 |"123" | 123 | | [] |"" | 0 | | {} |"[object Object]" | NaN | +-----------------+-------------------+---------------+ |
也很好地知道javascript的+操作符是左相关的,因为这决定了输出将是涉及多个+操作的情况。
杠杆作用因此,1+"2"将给出"12",因为涉及字符串的任何加法将始终默认为字符串串联。
你可以在这篇博文中阅读更多的例子(我写的免责声明)。