“script”标签应该被允许自我删除吗?

20

我们在工作场所就此进行了一些讨论,有些人支持这种行为,而有些人则反对。想听听你们的观点:

<html>
<body>
<div>
Test!
<script> document.body.removeChild(document.getElementsByTagName('div')[0]); </script>
</div>
</body>
</html>

上述脚本是否应该工作并执行它应该做的事情?首先,让我们看看这里发生了什么:

我有一个内嵌在<div>元素中的javascript。这个javascript将删除body中的子节点,这个子节点恰好包含了包含脚本本身的div。

现在,上述脚本在Firefox、Opera和IE8中都可以正常工作。但是IE6和IE7会弹出一个警告说它们无法打开页面。

让我们不要讨论IE应该如何处理这个问题(他们已经将其视为一个错误,并在IE8中修复了它)。这里的重点是,由于'SCRIPT'标签本身是DOM的一部分,它应该被允许做这样的事情吗?在这样的操作之后,它甚至应该存在吗?

编辑

如果我运行上述代码,Firefox、Opera、IE9等浏览器不会删除'script'标签。但是,document.getElementsByTagName('script').length返回0!

要理解我的意思,请在上面的代码中添加alert(document.getElementsByTagName('script').length); document.body.removeChild(document.getElementsByTagName('div')[0]);之前和之后。


当然,它已经被移除了。在脚本区域中定义的函数在执行后是否仍然存在?我会假设它会存在,但你可以争论它不应该存在。 - Noon Silk
一个从DOM中删除自身的代码片段?听起来有点像一个唯一目的是关闭自己的机器。就像http://sbus.blogspot.com/2008/04/machine-that-turns-itself-off.html或http://techblips.dailyradar.com/video/useless-machine-lego-prototype/。 - Tyler
@Silky是的,在脚本执行后该函数仍然存在。因此,IE9、Firefox、Opera和其他浏览器没有删除脚本标记,这意味着它们在某种程度上并不认为脚本是DOM的一部分,但实际上document.getElementsByTagName('script')是由它们支持的。因此,在某种程度上,浏览器似乎自相矛盾,它们在DOM操作中没有删除“script”标记,但非常清楚“script”是DOM的一部分!我们是否遗漏了什么? - Nischal
5
可能是DOM已经移除了它,但实际上JavaScript并不存在于DOM中,它存在于JavaScript解释器中。我不认为这真的是一个矛盾,但即使你这样认为,事实仍然存在:你做这件事情的原因很可能是非常错误的。 - Carson Myers
6个回答

8
如果问题是“是否应该允许脚本标签自我删除?”,我的想法是可以。毕竟,脚本标签可能会导致浏览器转到另一个页面,这种情况下整个页面(包括这样的脚本标签)都将从内存中移除。

好的,在上面的例子中,脚本标签并没有被移除。它仍然存在,你对此有什么看法? - Nischal
当你说“它仍然存在”时,你是指它仍然是DOM结构的一部分吗?如果是这样,那么在div元素被移除后,脚本元素的父元素是什么? - Will
1
有趣的问题。刚刚检查了这个行为。如果只有一个“script”标签,那么document.getElementsByTagName('script').length会给我一个0的计数!但我确定脚本标记仍然存在,因为在该脚本标记中编写的函数会被执行! - Nischal
1
脚本标签不再“存在”。只是JavaScript仍然在内存中加载。请参见:https://dev59.com/Nl_Va4cB1Zd3GeqPX-Rf#9082798 - Andrew Ensley

8
一个使用自我删除的例子是,例如一些长轮询技术,在几分钟后肯定会使DOM变得庞大。
JavaScript框架会添加和删除脚本元素作为日常例行程序。
例如,在jQuery中,getScript()会将脚本标签放置在文档头中,并在评估后立即删除它们。
他们这样做是为了保持DOM的清洁 - 否则标记只会不必要地增加。在评估之后,它们不再需要。
我唯一看到的缺点是调试 - 例如,Firefox与Firebug似乎迷失了这些脚本的下落,无法找到源行。(截至本文撰写时)。

6

事实上,你可以这样做:

var currentScript;
currentScript = document.currentScript || document.scripts[document.scripts.length - 1];
currentScript.parentNode.removeChild(currentScript);

1
请注意,当脚本标签具有“async”或“defer”属性时,不要使用此功能,因为如果不支持“currentScript”,则备用方案可能会返回另一个脚本标签。 - RiZKiT

2
该脚本从文档DOM树中移除DIV,并恰好在加载后移除脚本声明本身。因此,我认为这应该是可以接受的功能。
另外,直到加载并解释执行Javascript之前,脚本标签都将存在。在执行时,DIV(和SCRIPT)标签将从DOM树中删除,并仅作为将被垃圾回收的对象存在。
编辑:
我认为这里的主要观点是SCRIPT标记仅创建Javascript对象并将其放置在Javascript运行时引擎中的内存中(这与DOM完全不同)。一旦解释器完成了对SCRIPT标记的阅读,它就不再需要并且可以被丢弃(从DOM中删除)。
如果解释器被JS代码指示(通过按钮单击的处理程序)创建对DOM中其他对象的引用,则仍然可以访问Javascript函数。从事件处理程序调用的任何函数也将可访问。通过这种方式,您可以“遍历”从按钮->处理程序->其他函数/变量的调用堆栈。

以上情况下脚本不会被删除。为了确认这一点,您可以在删除子节点的代码下方创建一个JavaScript函数。将一个具有所述功能的onclick按钮放置在新的div中。onclick仍然有效,我希望您明白我的意思。 - Nischal
1
那是真的,Nischal。但你所创建的是一个引用,从DOM树中的按钮指向在现已删除的SCRIPT标签中创建的函数...这意味着该函数仍然存在于内存中,不会被垃圾回收。请参阅MSDN文章,了解为什么IE无法正确处理此问题。http://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspx - Jeff Meatball Yang

1

是的,这是一种有效的行为,因为脚本只会移除自己的DOM表示形式,而不是以这种方式移除自己。 实际上,脚本可以用完全不同的东西替换页面上自己的文本表示形式,而不需要重新运行。

例如:

var s = document.createElement('script');
s.textContent = 'alert("Hello, world!");'+
                'document.currentScript.textContent="alert(1)";';
                // BTW, behavior is the same for innerHTML
document.body.appendChild(s);

然而,除了想要保持DOM干净之外,几乎没有任何有效的理由使脚本自我删除或更改自身代码。此外,这不会隐藏您的代码,任何愿意查看它的人都可以看到。通常,这意味着您必须从其他代码中添加脚本,最好从那个脚本中使用document.body.removeChild(s);之类的东西。

-2

使用 JQuery(10.0.1以上版本)可以实现以下功能:

<!-- you call first to jquery -->
<script id="autoremove">
      $(function(){
           //your operations
                //action
                //action
           //remove the script
           $("#autoremove").remove();
      });
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接