代码{}
在JavaScript中是完全合法的,因为它表示Block。
但是,我注意到在Chrome *中嵌套了很多块({{...}}
)会引起很多问题:
为什么在这里发生堆栈溢出?
这是一个codepen说明问题(jsfiddle崩溃)。
在JSRoom中询问时,Zirak发现在chrome上,魔数是 3913 块,在Firefox上是 2555 。
什么被压入堆栈?为什么?
(*)我已经检查过了,它也出现在IE和Firefox中
更新:我已经检查过,IE无法可靠地避免堆栈溢出异常。它已经抛出了两次,但没有第三次。如果有任何读者使用IE,并且也愿意测试它的旧版本(例如IE8和9),请告诉我发生了什么,我将非常感谢。
最佳答案
首先,ghord是完全正确的。它是由解析器的递归性质引起的,因此请给他投票爱。但是需要证明,OP希望我将其作为单独的答案发布。
火狐浏览器
那么,在哪里可以找到如何完成的呢?问一些从事发动机制造的人。所以我转到#jsapi
上的irc://irc.mozilla.org
channel ,问他们:
这几乎就是答案。转到mozilla中央存储库并进行挖掘,我们有以下怀疑:
Parser<ParseHandler>::blockStatement
Parser<ParseHandler>::statements
因此,我们拥有的是:
statements
调用blockStatement
,后者解析该块,以查找另一个块,然后调用statements
调用blockStatement
,后者解析该块,以查找另一个块,然后调用statements
调用blockStatement
,后者解析该块,以查找另一个块,然后调用直到堆栈崩溃,我猜是here。
因此,我们有Firefox的源代码。
Chrome / Chromium /其他基于v8的版本
从Firefox上学习了教训,我进入了v8项目并寻找了一个名为
parser
的文件。果然在那里。接下来的事情是寻找何时解析一个块,所以我天真地搜索了
statements
,到达了有希望的ParseStatement。这是我们的幸运日,一个巨大的
switch
!我们关心的是the first case,它是另一个有希望的名字ParseBlock
的调用!实际上,是inside
ParseBlock
, we find a call到ParseStatement
。因此,很明显,我们有两个功能:Parser::ParseBlock
Parser::Parser::ParseStatement
他们像在Firefox中看到的那样互相打电话:
ParseStatement
调用ParseBlock
,后者解析该块,以查找另一个块,然后调用ParseStatement
调用ParseBlock
,后者解析该块,以查找另一个块,然后调用ParseStatement
调用ParseBlock
,后者解析该块,以查找另一个块,然后调用直到kaboom进入堆栈。
苹果浏览器
(很抱歉在上次编辑中将其称为“封闭源”!)Safari的js引擎是JavaScriptCore,它位于WebKit项目中。查找功能与在Chrome中查找功能几乎相同,因此让我们跳到有趣的部分:
Parser<LexerType>::parseSourceElements
Parser<LexerType>::parseStatement
Parser<LexerType>::parseBlockStatement
我们在中间有一个额外的功能,但是原理是一样的:
parseSourceElements
调用parseStatement
调用parseBlockStatement
,后者解析该块,以查找另一个块,然后调用parseSourceElements
调用parseStatement
调用parseBlockStatement
,后者解析该块,以查找另一个块,然后调用parseSourceElements
调用parseStatement
调用parseBlockStatement
,后者解析该块,以查找另一个块,然后调用繁荣
IE(以及其他所有开源软件,例如Opera)
……除非他们突然感到急切地要求公开消息,或者有进取心的员工与我们分享内部信息,否则这仍然是个谜。上面的两个出色的引擎以相同的方式进行操作,因此我们可以假定其他浏览器也以类似的方式进行操作。
如果浏览器没有崩溃,那将是一个有趣的问题,但是这个答案不能指望有人咳嗽。