alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);
这段代码的输出是:fail
。为什么?
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);
这段代码的输出是:fail
。为什么?
正如@Mauricio 评论的那样(![]+[])[+[]]
是“f”(“false”的第一个字符),(![]+[])[+!+[]])
是“a”,等等......
它是如何工作的?
让我们检查第一个字符 'f':
(![]+[])[+[]]; // 'f'
表达式的第一部分——在括号之间——由 组成![]+[]
,加法运算符的第一个操作数是![]
,它将产生false
,因为数组对象——与任何其他对象实例一样——是真的,并且应用逻辑 (!) 非一元运算符,false
例如,它产生值。
![]; // false, it was truthy
!{}; // false, it was truthy
!0; // true, it was falsey
!NaN; // true, it was falsey
在它之后,我们有加法的第二个操作数,一个空数组,,[]
这只是为了将false
值转换为字符串,因为空数组的字符串表示只是一个空字符串,相当于:
false+[]; // "false"
false+''; // "false"
最后一部分,括号后的那对方括号,它们是属性访问器,它们接收一个表达式,该表达式由再次应用于空数组的一元加运算符形成。
一元加运算符所做的是类型转换,Number
例如:
typeof +"20"; // "number"
再一次,这适用于一个空数组,正如我之前所说的,一个数组的字符串表示是一个空字符串,当你将一个空字符串转换为数字时,它被转换为零:
+[]; // 0, because
+[].toString(); // 0, because
+""; // 0
因此,我们可以通过一些步骤将表达式“解码”为:
(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0]; // "f"
请注意,通过在字符串值上使用括号表示法来访问字符不是 ECMAScript 3rd 的一部分。版本规范,(这就是该charAt
方法存在的原因)。
然而,这种表示字符串字符的“索引属性”已在 ECMAScript 5 上标准化,甚至在标准化之前,该功能在很多浏览器中都可用(甚至在 IE8(标准模式)中)。