Joh*_*nGa 1613 javascript syntax
这是有效的,并返回"10"JavaScript中的字符串(此处更多示例):
console.log(++[[]][+[]]+[+[]])Run Code Online (Sandbox Code Playgroud)
为什么?这里发生了什么?
pim*_*vdb 2032
如果我们把它分开,这个混乱就等于:
++[[]][+[]]
+
[+[]]
Run Code Online (Sandbox Code Playgroud)
在JavaScript中,确实如此+[] === 0.+将某些东西转换为数字,在这种情况下,它将归结为+""或0(参见下面的规范细节).
因此,我们可以简化它(++优先于+):
++[[]][0]
+
[0]
Run Code Online (Sandbox Code Playgroud)
因为[[]][0]意味着:从第一个元素中获取[[]],确实如此:
[[]][0]返回内部数组([]).由于引用它是错误的说[[]][0] === [],但让我们调用内部数组A以避免错误的表示法.++,因为++[[]][0]意味着'递增一'.Number(A) + 1; 换句话说,它总是一个数字(+A + 1不一定会返回一个数字,而[]总是这样 - 感谢Tim Down指出这一点).同样,我们可以将混乱简化为更清晰的东西.让我们替换A回来+[]:
(+[] + 1)
+
[0]
Run Code Online (Sandbox Code Playgroud)
在JavaScript中,这也是正确的:0因为""(加入一个空数组),所以:
1,和1,和(+[] + 1) === (+"" + 1)让我们进一步简化它:
1
+
[0]
Run Code Online (Sandbox Code Playgroud)
此外,在JavaScript中也是如此:(+"" + 1) === (0 + 1)因为它使用一个元素连接数组.连接将连接分隔的元素(0 + 1) === 1.使用一个元素,您可以推断出该逻辑将导致第一个元素本身.
所以,最后我们得到(number + string = string):
"1" + "0" === "10" // Yay!
Run Code Online (Sandbox Code Playgroud)
规格细节[0] == "0":
这是一个非常迷宫,但要做到,这一点,首先它被转换为字符串,因为这是+说:
11.4.6一元+算子
一元+运算符将其操作数转换为数字类型.
生产UnaryExpression:+ UnaryExpression的计算方法如下:
设expr是评估UnaryExpression的结果.
返回ToNumber(GetValue(expr)).
"0" 说:
宾语
应用以下步骤:
让primValue为ToPrimitive(输入参数,提示字符串).
返回ToString(primValue).
"1" 说:
宾语
返回Object的默认值.通过调用对象的[[DefaultValue]]内部方法,传递可选提示PreferredType来检索对象的默认值.对于8.12.8中的所有本机ECMAScript对象,此规范定义了[[DefaultValue]]内部方法的行为.
+ 说:
8.12.8 [[DefaultValue]](提示)
当使用提示字符串调用O的[[DefaultValue]]内部方法时,将执行以下步骤:
设toString是使用参数"toString"调用对象O的[[Get]]内部方法的结果.
如果IsCallable(toString)为真,那么,
一个.令str为调用toString的[[Call]]内部方法的结果,其中O为此值,且为空参数列表.
湾 如果str是原始值,则返回str.
该===数组的说:
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]]内部方法的结果作为此值和空参数列表.
所以+[]归结为+[],因为+.
同样,ToNumber()定义为:
11.4.6一元+算子
一元+运算符将其操作数转换为数字类型.
生产UnaryExpression:+ UnaryExpression的计算方法如下:
设expr是评估UnaryExpression的结果.
返回ToNumber(GetValue(expr)).
ToPrimitive()定义为[[DefaultValue]]:
StringNumericLiteral ::: [empty]的MV为0.
所以.toString,从而+[].
She*_*hef 121
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]
Run Code Online (Sandbox Code Playgroud)
然后我们有一个字符串连接
1+[0].toString() = 10
Run Code Online (Sandbox Code Playgroud)
Tim*_*own 60
以下内容改编自一篇博客文章,回答了我在此问题仍未结束时发布的问题.链接是ECMAScript 3规范的(HTML副本),仍然是当今常用Web浏览器中JavaScript的基线.
首先,评论:这种表达式永远不会出现在任何(理智的)生产环境中,并且只是作为一种练习用于读者如何知道JavaScript的脏边缘.JavaScript运算符在类型之间隐式转换的一般原则是有用的,一些常见的转换也是如此,但在这种情况下的大部分细节都不是.
该表达式++[[]][+[]]+[+[]]最初可能看起来相当模糊和模糊,但实际上相对容易分解为单独的表达式.下面我简单地添加括号以便清楚; 我可以向你保证他们什么都不会改变,但如果你想验证那么你可以随意阅读有关分组操作员的信息.因此,表达式可以更清楚地写成
( ++[[]][+[]] ) + ( [+[]] )
Run Code Online (Sandbox Code Playgroud)
打破这一点,我们可以通过观察+[]评估来简化0.为了满足自己为什么这是真的,请查看一元+运算符,然后按照稍微弯曲的路径,最后使用ToPrimitive将空数组转换为空字符串,最后0由ToNumber转换为空字符串.我们现在可以替换0以下每个实例+[]:
( ++[[]][0] ) + [0]
Run Code Online (Sandbox Code Playgroud)
已经更简单了.至于++[[]][0],这是前缀增量operator(++)的组合,一个数组文字定义一个数组,单个元素本身是一个空数组([[]])和一个属性访问器([0])在数组文字定义的数组上调用.
所以,我们可以简化[[]][0]到公正[],我们拥有++[],对吗?实际上,情况并非如此,因为评估++[]会引发错误,这可能最初看起来令人困惑.然而,稍微考虑一下它的性质++就会明确:它用于增加变量(例如++i)或对象属性(例如++obj.count).它不仅会评估一个值,还会在某个地方存储该值.在这种情况下++[],它无处可放新值(无论它是什么),因为没有引用要更新的对象属性或变量.在规范方面,这由内部PutValue操作覆盖,该操作由前缀增量运算符调用.
那么,做++[[]][0]什么呢?那么,通过类似的逻辑+[],内部数组被转换为,0并且该值递增1以给出最终值1.0外部数组中的属性值更新为1,整个表达式的计算结果为1.
这让我们失望了
1 + [0]
Run Code Online (Sandbox Code Playgroud)
...这是加法运算符的简单用法.两个操作数首先转换为基元,如果原始值是字符串,则执行字符串连接,否则执行数字加法.[0]转换为"0",所以使用字符串连接,生成"10".
作为最后的一点,可能不会立即显而易见的是,覆盖其中一个toString()或多个valueOf()方法Array.prototype将改变表达式的结果,因为在将对象转换为原始值时,如果存在,则检查并使用它们.例如,以下内容
Array.prototype.toString = function() {
return "foo";
};
++[[]][+[]]+[+[]]
Run Code Online (Sandbox Code Playgroud)
......产生"NaNfoo".为什么会发生这种情况留给读者练习...
小智 23
让我们简单一点:
++[[]][+[]]+[+[]] = "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"
Run Code Online (Sandbox Code Playgroud)
小智 13
这个评估为相同但略小
+!![]+''+(+[])
Run Code Online (Sandbox Code Playgroud)
所以评估为
+(true) + '' + (0)
1 + '' + 0
"10"
Run Code Online (Sandbox Code Playgroud)
所以现在你有了,试试这个:
_=$=+[],++_+''+$
Run Code Online (Sandbox Code Playgroud)
cus*_*der 10
++[[]][+[]]+[+[]]
^^^
|
v
++[[]][+[]]+[0]
^^^
|
v
++[[]][0]+[0]
^^^^^^^
|
v
++[]+[0]
^^^
|
v
++[]+"0"
^^^^
|
v
++0+"0"
^^^
|
v
1+"0"
^^^^^
|
v
"10"
Run Code Online (Sandbox Code Playgroud)
运算+符通过 强制任何非数字操作数.valueOf()。如果不返回数字,则.toString()调用。
我们可以简单地验证这一点:
const x = [], y = [];
x.valueOf = () => (console.log('x.valueOf() has been called'), y.valueOf());
x.toString = () => (console.log('x.toString() has been called'), y.toString());
console.log(`+x -> ${+x}`);Run Code Online (Sandbox Code Playgroud)
因此与强制转换为 的数字+[]相同。""0
如果任何操作数是字符串,则+连接。
+ []计算为0 [...]然后对任何事物进行求和(+运算)将数组内容转换为包含用逗号连接的元素组成的字符串表示.
任何其他类似于获取数组的索引(具有比+操作更重要的优先级)是有序的并且没有什么有趣的.
也许评估"10"没有数字的表达式的最短方法是:
+!+[] + [+[]] // "10"
-~[] + [+[]] // "10"
Run Code Online (Sandbox Code Playgroud)
+!+[]:
+[]被评估为0。!0被评估为true。+true被评估为1。-~[]与-(-1)被评估为的相同1。[+[]]:
+[] 被评估为 0[0]是一个具有单个元素的数组0。然后,JS 计算1 + [0], 一个Number + Array表达式。然后 ECMA 规范起作用:+运算符通过调用ToPrimitive和ToString抽象操作将两个操作数转换为字符串。如果表达式的两个操作数都只是数字,则它作为加法函数运行。诀窍是数组很容易将它们的元素强制转换为连接的字符串表示形式。
一些例子:
1 + {} // "1[object Object]"
1 + [] // "1"
1 + new Date() // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"
[] + [] // ""
[1] + [2] // "12"
{} + {} // "[object Object][object Object]" ¹
{a:1} + {b:2} // "[object Object][object Object]" ¹
[1, {}] + [2, {}] // "1,[object Object]2,[object Object]"
Run Code Online (Sandbox Code Playgroud)
¹:请注意,每一行都在表达式上下文中进行计算。第一个{…}是一个对象字面量,而不是一个块,就像在语句上下文中的情况一样。在一个REPL,你可能会看到{} + {}造成NaN的,因为大多数REPLs在一份声明中上下文中进行操作; 这里,第一个{}是块,代码等价于{}; +{};,最后的表达式语句(其值成为完成记录的结果)是NaN因为一元+将对象强制为数字。
一步一步地,+将值转换为一个数字,如果你添加到一个空数组+[]......因为它是空的并且等于0,它将
所以从那里开始,现在看看你的代码,它是++[[]][+[]]+[+[]]......
他们之间还有加号++[[]][+[]]+[+[]]
所以这些[+[]]将返回,[0]因为它们有一个空数组,该数组被转换为0另一个数组......
所以想象一下,第一个值是一个二维数组,里面有一个数组......所以[[]][+[]]将等于[[]][0]which 将返回[]......
最后++将其转换并增加到1......
所以你可以想象,1+"0"将是"10"......
| 归档时间: |
|
| 查看次数: |
197849 次 |
| 最近记录: |