(![]+[])[+[]]...解释为什么这有效

2022-08-30 05:00:09
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

此代码的输出为:。为什么?fail


答案 1

正如@Mauricio评论的那样,是“f”(“false”的第一个字符),是“a”,等等......(![]+[])[+[]](![]+[])[+!+[]])

它是如何工作的?

让我们检查第一个字符“f”:

(![]+[])[+[]]; // 'f'

表达式的第一部分(在括号之间)由 组成,加法运算符的第一个操作数是,它将产生 ,因为数组对象(与任何其他 Object 实例一样)是真实的,并且应用逻辑 (!)不是一元运算符,它产生值,例如。![]+[]![]falsefalse

![]; // false, it was truthy
!{}; // false, it was truthy
!0;  // true, it was falsey
!NaN;  // true, it was falsey

在它之后,我们有加法的第二个操作数,一个空数组,,这只是为了将值转换为String,因为空数组的字符串表示只是一个空字符串,等价于:[]false

false+[]; // "false"
false+''; // "false"

最后一部分,括号后面的一对方括号,它们是属性访问器,它们接收一个表达式,该表达式由再次应用于空数组的一元加号运算符形成。

一元加号运算符的作用是将类型转换为 ,例如:Number

typeof +"20"; // "number"

还有一次,这适用于空数组,正如我之前所说,数组的字符串表示形式是空字符串,当您将空字符串转换为数字时,它将转换为零:

+[]; // 0, because
+[].toString(); // 0, because
+""; // 0

因此,我们可以在某些步骤中将表达式“解码”为:

(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0];  // "f"

请注意,通过在字符串值上使用括号表示法来访问字符不是 ECMAScript 第 3 版规范的一部分(这就是该方法存在的原因)。charAt

然而,这种表示字符串字符的“索引属性”在 ECMAScript 5 上是标准化的,甚至在标准化之前,该功能在很多浏览器中都可用(即使在 IE8(标准模式)中)。


答案 2