为什么不克隆<script>标签执行?</script>

时间:2015-02-27 18:06:01

标签: javascript dom

克隆&lt; script&gt;标签不执行。为什么?

示例:

<script id="hello">
  console.log("hello execution count ", window.helloCount++);
</script>

<script id="action">
  document.body.appendChild(
    document.getElementById('hello').cloneNode(true));
  console.log('cloned the script');
</script>

执行后,文档中有两个hello脚本,但只有一个已执行。

http://jsbin.com/zuxoro/1/edit?html,console,output

这是我正在处理的一个更大问题的一部分,所以我知道这是一件蠢事。

3 个答案:

答案 0 :(得分:6)

W3C HTML5 specification需要此行为。

每个<script>元素都有一个名为“已启动”的属性标记。规范说:

  

最初,脚本元素必须取消设置此标志(脚本块在创建时不会“已经启动”)。 如果在要克隆的元素上设置了脚本元素的克隆步骤,则必须在副本上设置“已启动”标志。

然后,后来:

  

如果脚本元素被标记为“已经开始”,则用户代理必须在此时中止这些步骤。该脚本未执行。

解决方案不是克隆脚本元素,而是创建使用相同内容填充的全新元素。

答案 1 :(得分:1)

原则上,浏览器在页面上执行<script>时执行以下操作:

如果在执行以下操作之前未执行脚本<script>

  1. <script>;
  2. 获取文字
  3. 致电eval(thatScriptText);
  4. <script> DOM节点标记为已执行;
  5. 当您克隆节点时,它也会获得内部“已执行”标志,这会阻止脚本进一步执行。

    解决方案:如果您希望重新执行脚本,请执行步骤#1和#2。在这种情况下不需要克隆。

答案 2 :(得分:1)

我不知道为什么它不适用于cloneNode,但您可以通过将innerHTML复制到新的脚本节点来实现相同的结果。

var clone = document.createElement('script');
clone.innerHTML = document.getElementById('hello').innerHTML;
document.body.appendChild(clone);
console.log('copied the script');
<script>
  window.helloCount = 1;
</script>
<script id="hello">
  console.log("hello execution count ", window.helloCount++);
</script>
<div>Copied scripts do execute</div>