(![]+[])[+[]]... 解释为什么会这样

IT技术 javascript
2021-02-01 07:12:27
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

这段代码的输出是:fail为什么?

1个回答

正如@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(标准模式)中)。

@JoshStodola 好吧,大约 3 个月后,进一步澄清。在这种情况下,“i”来自“undefined”,是的,但这里还涉及另一个技巧。代码将 "false" 连接到 "undefined" 以形成"falseundefined"(使用: 构造[![]]+[][[]]),其中 "i" 的索引为 10。+!+[]+[+[]]给出"10". 这用于提取“i”(如果字符串索引可以明显地强制为整数,则可以在 javascript 中使用它们)。产生它的最终构造是:([![]]+[][[]])[+!+[]+[+[]]]
2021-03-14 07:12:27
@rlemon,int该语言没有数据类型,实际上所有数字都是双精度 64 位格式(IEEE 754 值),即使某些运算符在内部使用整数值(如按位运算符),结果始终是 double . 'i'进来从这个例子undefined,但它可能来自Infinity例如:(+!+[]/+[+[]]+[])[!+[]+!+[]+!+[]]=> (1/0+'')[3]=> (Infinity+'')[3]=>'i'
2021-04-03 07:12:27
“我”从何而来?
2021-04-07 07:12:27
@JTA:我希望我会通过的:-D
2021-04-09 07:12:27
只是希望这永远不是面试问题。
2021-04-10 07:12:27