为什么下面的脚本打印33而不是31?
<script>
var i = 1;
document.write("<script> i=3; document.write(i); </scr" + "ipt>");
document.write(i);
</script>
这个打印31,有什么区别?
<script>
var i = 1;
document.write("<script> i=3; document.write(i); </scr" + "ipt>" + i);
</script>
答案 0 :(得分:2)
这是它的工作方式:
i
的变量,其值为1
。您在文档中编写了一个新脚本
2.1。此新脚本将i
重新定义为3
。
2.2。该脚本将i
(请记住,现在为3
)写入文档。
您再次写i
(从您重新定义它时,值仍然是相同的,3
)到文档。
33
,因为您曾两次撰写3
。
这是第二个块的顺序:
i
定义变量1
。i
,创建"<script> i=3; document.write(i); </script>1"
(注意最后的1
,这是连接)JavaScript将新的连接字符串写入文档。
3.1。 i
被重新定义为3
。
3.2。 document.write
&#39; i
(之前已重新定义为3
)。
由于连接和"3<script> i=3; document.write(i); </script>1"
,您最终将document.write
作为最终文档。很明显,<script>
的内容并不可见。所以你最终得到了31
。
答案 1 :(得分:2)
为了使您的第一个示例的输出为31,在解析器对该输出执行任何操作之前,最外层的脚本块必须一直运行,生成其所有输出。这是一种完全合理的方式来认为它会起作用(我认为这种方式可以使用多年);它只是不正确。 :-)浏览器比这更主动。
浏览器的解析器和JavaScript引擎必须协同处理不使用async
或defer
属性的脚本标记。有两个关键的事情:
当解析器看到一个完整的script
块时,它会突然停止并将其交给JavaScript引擎立即运行。
调用document.write
向解析器提供新令牌;如果解析器看到一个完整的令牌,它将在调用document.write
期间处理。如果该完整令牌是脚本块,则“处理它”涉及在当前调用期间再次调用JavaScript引擎。您可以将每个document.write
调用视为对解析器的调用,并将每个完整的脚本块视为对JavaScript引擎的调用。与函数调用类似,这些可以嵌套。
第二点是你看到33而不是31的原因。你用document.write
撰写的剧本在期间执行时调用document.write
,而不是之后,因此i
在3
完成之前更新为document.write
(并输出)。因此,当您到达主脚本块末尾的document.write
时,i
已经更改为3
,并且已经输出一次。
在您的第二个示例中,您使用i
之前调用document.write
(当您将其附加到文本中时),所以当然您会看到i
就像那样,1
。
这可能会使通话顺序更加清晰:
<script>
document.write("<script>document.write('a');</scr" + "ipt>");
document.write('b');
</script>
结果为ab
,而不是ba
。第一个document.write
输出的代码在最后document.write
之前运行,因此中间document.write
的输出显示在最后一个{{1}}的输出之前。< / p>
答案 2 :(得分:0)
在第一种情况下,在第一种情况下注入document.write
重新定义变量i,因此第二种document.write
也会打印出来。
在第二种情况下,您只有一个document.write,它将原始值i = 1附加到注入document.write
的输出。
有趣的是,有人可能会在这里期待另一种组合&#39; 13&#39;)))