为什么++ ] ] + ]返回字符串“10”?
这是有效的,并返回JavaScript中的字符串"10"
( 更多示例 ):
++[[]][+[]]+[+[]]
为什么? 这里发生了什么?
如果我们把它分开,混乱等于:
++[[]][+[]] + [+[]]
在JavaScript中, +[] === 0
。 +
把东西转换成数字,在这种情况下它会降到+""
或0
(见下面的详细说明)。
因此,我们可以简化它( ++
优于+
):
++[[]][0] + [0]
因为[[]][0]
意味着:从[[]]
获取第一个元素,这是真的:
-
[[]][0]
返回内部数组([]
)。 由于引用,说[[]][0] === []
,但是让我们调用内部数组A
来避免错误的表示法。 -
++[[]][0] == A + 1
,因为++
表示“按1递增”。 -
++[[]][0] === +(A + 1)
; 换句话说,它总是一个数字(+1
不一定会返回一个数字,而++
总是这样 – 感谢Tim Down指出这一点)。
再一次,我们可以把这个烂摊子简化成更清晰的东西。 我们用[]
代替A
:
+([] + 1) + [0]
在JavaScript中,这也是如此: [] + 1 === "1"
,因为[] == ""
(加入一个空数组),所以:
-
+([] + 1) === +("" + 1)
,和 -
+("" + 1) === +("1")
和 -
+("1") === 1
让我们更简化一下:
1 + [0]
而且,这在JavaScript中是正确的: [0] == "0"
,因为它是用一个元素连接一个数组。 连接将连接由。分隔的元素。 用一个元素,你可以推断出这个逻辑将导致第一个元素本身。
所以,最后我们得到(数字+字符串=字符串):
1 + "0" === "10" // Yay!
+[]
规格细节:
这是一个迷宫,但要做+[]
,首先它被转换为一个字符串,因为这就是+
说:
11.4.6一元+运算符
一元+运算符将其操作数转换为数字类型。
生产UnaryExpression:+ UnaryExpression的计算方法如下:
让expr是评估UnaryExpression的结果。
返回ToNumber(GetValue(expr))。
ToNumber()
表示:
目的
应用以下步骤:
设primValue为ToPrimitive(输入参数,提示字符串)。
返回ToString(primValue)。
ToPrimitive()
说:
目的
返回对象的默认值。 通过调用对象的[[DefaultValue]]内部方法来检索对象的默认值,并传递可选的提示PreferredType。 本规范针对8.12.8中的所有本地ECMAScript对象定义了[[DefaultValue]]内部方法的行为。
[[DefaultValue]]
说:
8.12.8 [[DefaultValue]](提示)
当使用提示字符串调用O的[[DefaultValue]]内部方法时,采取以下步骤:
让toString是使用参数“toString”调用对象O的[[Get]]内部方法的结果。
如果IsCallable(toString)为true,
一个。 让str是调用toString的[[Call]]内部方法的结果,其中O作为此值和一个空的参数列表。
湾 如果str是一个原始值,则返回str。
数组的.toString
表示:
15.4.4.2 Array.prototype.toString()
当调用toString方法时,采取以下步骤:
让数组成为在此值上调用ToObject的结果。
让func成为使用参数“join”调用数组的[[Get]]内部方法的结果。
如果IsCallable(func)为false,则让func成为标准的内置方法Object.prototype.toString(15.2.4.2)。
返回调用func提供数组的[[Call]]内部方法的结果作为这个值和一个空的参数列表。
所以+[]
归结为+""
,因为[].join() === ""
。
再次, +
被定义为:
11.4.6一元+运算符
一元+运算符将其操作数转换为数字类型。
生产UnaryExpression:+ UnaryExpression的计算方法如下:
让expr是评估UnaryExpression的结果。
返回ToNumber(GetValue(expr))。
ToNumber
被定义为""
为:
StringNumericLiteral ::: [空]的MV是0。
所以+"" === 0
,因此+[] === 0
。
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1 [+[]] => [0]
然后我们有一个字符串连接
1+[0].toString() = 10
以下是从博客文章改编,回答这个问题,我发布时,这个问题仍然关闭。 链接是(ECMAScript 3规范的HTML副本),仍然是当今常用Web浏览器中JavaScript的基准。
首先,一个评论:这种表达永远不会出现在任何(理智的)生产环境中,而只是作为练习读者如何知道JavaScript的肮脏边缘。 JavaScript运算符在类型之间隐式转换的一般原则是有用的,一些常见的转换也是如此,但是这种情况下的大部分细节并不是这样。
表达式++[[]][+[]]+[+[]]
最初可能看起来相当有说服力,而且比较容易分解成不同的表达式。 下面我简单地加了括号, 我可以向你保证,他们什么都不会改变,但如果你想验证,那么随时阅读有关分组运算符 。 所以,表达可以更清楚地写成
( ++[[]][+[]] ) + ( [+[]] )
打破这一点,我们可以通过观察+[]
求值为0
来简化。 为了满足自己为什么这是真实的,检查出一元+运算符,并遵循稍微曲折的轨迹,结束ToPrimitive空数组转换为空字符串,然后通过ToNumber最终转换为0
。 我们现在可以用0
代替+[]
每个实例:
( ++[[]][0] ) + [0]
更简单了。 至于++[[]][0]
,这是一个前缀增量运算符 ( ++
)的组合,它定义了一个数组,其中单个元素本身是一个空数组( [[]]
),一个属性访问器 ( [0]
)调用由数组文字定义的数组。
所以,我们可以将[[]][0]
简化为[]
,我们有++[]
,对吧? 事实上,情况并非如此,因为评估++[]
会抛出一个错误,最初可能会让人困惑。 然而,有一点关于++
的本质的想法清楚地表明:它用于递增一个变量(例如++i
)或一个对象属性(例如++obj.count
)。 它不仅评估价值,还将价值存储在某个地方。 在++[]
的情况下,由于没有引用要更新的对象属性或变量,无处可放新值(不管它是什么)。 在规范中,这由内部PutValue操作覆盖,该操作由前缀增量运算符调用。
那么, ++[[]][0]
做什么的? 那么,通过与+[]
类似的逻辑,内部数组被转换为0
并且这个值增加1
,给我们最终值1
。 外部数组中的属性0
的值更新为1
,整个表达式的计算结果为1
。
这留下了我们
1 + [0]
…这是加法运算符的简单使用。 两个操作数首先被转换为原语 ,如果原始值是一个字符串,则执行字符串连接,否则执行数字加法。 [0]
转换为"0"
,所以使用字符串连接,产生"10"
。
作为一个最后的旁观,可能不会立即明白的是,覆盖Array.prototype
的toString()
或valueOf()
方法将改变表达式的结果,因为如果在转换将对象转换为原始值。 例如,以下
Array.prototype.toString = function() { return "foo"; }; ++[[]][+[]]+[+[]]
制作"NaNfoo"
为什么发生这种情况只能作为读者的练习…
让我们来简单说一下:
++[[]][+[]]+[+[]] = "10" var a = [[]][+[]]; var b = [+[]]; // so a == [] and b == [0] ++a; // then a == 1 and b is still that array [0] // when you sum the var a and an array, it will sum b as a string just like that: 1 + "0" = "10"
这一个评估相同,但有点小
+!![]+''+(+[])
- [] – 是一个数组被转换成当你加或减的转换为0,因此+ [] = 0
- ![] – 计算结果为false,因此!! []的计算结果为true
- + !! [] – 将true转换为数值,计算结果为true,所以在这种情况下为1
- +'' – 将空字符串附加到表达式中,使数字转换为字符串
- + [] – 评估为0
所以评估
+(true) + '' + (0) 1 + '' + 0 "10"
所以现在你明白了,试试这个:
_=$=+[],++_+''+$
+ []求值为0,然后求和(+操作),任何东西都将数组内容转换为由逗号连接的元素组成的字符串表示形式。
任何其他喜欢采取数组的索引(比+操作具有更高的优先级)是序数,没有什么有趣的。
也许最简单的方法来评估表达为“10”没有数字是:
+!+[] + [+[]]
//“10”
-~[] + [+[]]
//“10”
// ==========说明========== \\
+!+[]
: +[]
转换为0. !0
转换为true
。 +true
转换为1. -~[]
= -(-1)
这是1
[+[]]
: +[]
转换为0. [0]
是一个具有单个元素0的数组。
然后JS评估1 + [0]
,从而Number + Array
表达式。 然后ECMA规范起作用: +
运算符通过调用基本Object
原型的toString()/valueOf()
函数将两个操作数转换为一个字符串。 如果一个表达式的两个操作数只是数字,它就作为一个加法函数。 诀窍是数组很容易将它们的元素转换为连接的字符串表示形式。
一些例子:
1 + {} // "1[object Object]" 1 + [] // "1" 1 + new Date() // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"
NaN
有两个Objects
添加结果:
[] + [] // "" [1] + [2] // "12" {} + {} // NaN {a:1} + {b:2} // NaN [1, {}] + [2, {}] // "1,[object Object]2,[object Object]"
- 一元加上给定的字符串转换为数字
- 给定字符串的递增运算符转换并递增1
- [] ==''。 空的字符串
-
+''或+ []评估0。
++[[]][+[]]+[+[]] = 10 ++[''][0] + [0] : First part is gives zeroth element of the array which is empty string 1+0 10