关于javascript:(![] + [])[+ []] …解释为什么会这样

(![]+[])[+[]]… Explain why this works

1
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

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

顺便问一下,(![]+[])[+!+[]] == 'false'[1]对吗?但是为什么是![]+[] =="false",为什么是+!+[] == 1


正如@mauricio所评论的,(![]+[])[+[]]是"f"(第一个字符是"false"),(![]+[])[+!+[]])是"a"等…

它是如何工作的?

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

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

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

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

在它之后,我们得到加法的第二个操作数,一个空数组,[],这是为了将false值转换为字符串,因为空数组的字符串表示形式只是一个空字符串,相当于:

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

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

一元加号运算符所做的是类型转换,到Number,例如:

1
typeof +"20"; //"number"

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

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

因此,我们可以通过以下步骤"解码"表达式:

1
2
3
4
5
(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0];  //"f"

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

然而,这种表示字符串字符的"索引属性"在ECMAScript 5上进行了标准化,甚至在标准化之前,该功能在许多浏览器(甚至在IE8(标准模式))中都可用。