我有兴趣了解JavaScript的内部结构。我试过阅读SpiderMonkey和Rhino的来源,但是我的头脑很复杂。
我问的原因是:为什么会这样?
(![]+[])[+!![]+[]]
生成"a"
(Å=[],[µ=!Å+Å][µ[È=++Å+Å+Å]+({}+Å)[Ç=!!Å+µ,ª=Ç[Å]+Ç[+!Å],Å]+ª])()[µ[Å]+µ[Å+Å]+Ç[È]+ª](Å)
生成alert(1)
?来源:http://sla.ckers.org/forum/read.php?24,32930,page=1。
在该论坛上还有更多关于JavaScript奇怪的例子,我想从编程的角度来了解它在Web应用程序安全性方面的作用。
答案 0 :(得分:16)
如果你想了解为什么那些奇怪的表达式会像他们一样工作,你可以打开firebug控制台并自己做实验。我做了,我得到![]
为false
,!![]
为true
,将数组添加到布尔值(false+[]
或true+[]
)生成此值的字符串版本(false+[]="false"
)。
这样的表达归结为:
"false"["1"]
这显然是“一个”
答案 1 :(得分:12)
为什么(![]+[])[+!![]+[]]
会产生“a”
一步一步:在(![]+[])
和[+!![]+[]]
中进行解析。第一位已经由artemb解释:[]
是一个数组。否定它,![]
计算为布尔值false
- 这就是!
在应用于非null
或未定义的内容时的工作方式。再次如artemb所指出的那样,附加此+[]
会强制将布尔值转换为字符串。那是因为+
是一个字符串连接运算符。然后将布尔值false
转换为其字符串表示形式"false"
。
然后,第二位[+!![]+[]]
。首先,外部[
和]
用于处理前面的字符串,我们刚刚将其作为一个字符数组等于"false"
。通过在[
和]
中放置一个整数索引,可以得到特定索引处的字符。剩下的就是+!![]+[]
这包括4件:+
,!![]
,+
和[]
。首先评估!![]
。我们已经看到![]
是一个布尔false
,所以在另一个!
之前加上否定它,并产生true
。接下来发生的事情是+
中的+!![]
被应用,并且通过应用+
,它将布尔值true
转换为数字表示,即1
(所以+true
是1
)后面的+[]
从1
产生"1"
再次生成一个字符串,但它没有意义,更短的表达(![]+[])[+!![]]
已生成a
。追加+[]
也不会造成伤害,结果表达式只是["1"]
而不是[1]
。我的预感是,当[]
应用于数组时,[]
内的任何内容都会被强制转换为数字,"1"
会再次给1
。所以无论哪种方式,+!![]+[]
评估为1
,最后表达式为:"false"[1]
,它说:从字符串"false"
中获取索引1处的字符,并且因为默认情况下,数组从javascript中的0
开始,这是"false"
和a
的第二个字符。
答案 2 :(得分:2)
为什么(![] + [])[+ !! [] + []]产生“a”
!expr
- 在expr上调用ToBoolean并翻转布尔值。换句话说,当与not运算符一起使用时,诸如空数组之类的truthy值将产生错误。a + b
- 两个表达式都通过内部ToPrimitive运行。如果结果值是字符串,则执行字符串连接。否则,基元将通过ToNumber运行并添加。对象的ToPrimitive(包含数组)将尝试toString和valueOf。 Array.prototype.toString充当没有参数的调用连接。因此,![] + [] = false + "" = "false"
!![] == true
,一元加号运算符将表达式转换为数字,因此1
。同样,数组转换为""
所以+!![]+[] == "1"
。("false")["1"] == "a"
另一种表达方式可以用类似的方式归结。它使用unicode字符串来搞砸它并且它更长,但就像直接“解析”一样。
答案 3 :(得分:1)
我建议您获取并阅读: