如何从DOM中卸载包含其所有已定义对象的JavaScript资源?
我开发了一个简单的框架,可以将html片段加载到“主”html中。每个片段都是自包含的,可能包含对其他JS和CSS文件的引用。解析JS和CSS资源并将其动态添加到html中。当从DOM中删除/替换片段时,我想删除它的JS和CSS。
如果我删除了下面示例中的script元素,则page1.js中定义的函数仍然可用。
<html>
<head>
<script src="page1.js" type="text/javascript"></script>
</head>
<body>
...
有没有办法从DOM中卸载page1.js对象?
=========我使用的测试代码=======
我尝试了下面评论中的建议;使用清理功能删除添加的对象 - 但即使这样也会失败。我用来测试的来源:
<html>
<head>
<script type="text/javascript">
function loadJSFile(){
var scriptTag = document.createElement("script");
scriptTag.setAttribute("type", "text/javascript");
scriptTag.setAttribute("src", "simple.js");
var head = document.getElementsByTagName("head")[0];
head.appendChild(scriptTag);
}
function unloadJSFile(){
delete window.foo;
delete window.cleanup;
alert("cleanedup. typeof window.foo is " + (typeof window.foo));
}
</script>
</head>
<body>
Hello JavaScript Delete
<br/>
<button onclick="loadJSFile();">Click to load JS</button>
<br/>
<button onclick="foo();">call foo()</button>
<br/>
<button onclick="unloadJSFile();">Click to unload JS</button>
</body>
</html>
simple.js来源:
var foo = function(){
alert("hello from foo");
}
答案 0 :(得分:14)
这不可能。
执行脚本时,函数定义将添加到全局window
对象中。可能存在附加到函数的调试符号,用于指示函数的来源,但脚本无法使用此信息。
关于实现这样的事情的唯一方法是在脚本中创建一个伪命名空间,然后在完成后抛弃整个命名空间。但是,这个问题告诉我你正试图以错误的方式做某事。也许详细说明你的场景将有助于我们提供替代解决方案。
答案 1 :(得分:6)
不,那是不可能的。您可以构建一个简单的清理函数,删除该文件中定义的所有变量:
var foo = 'bar';
var cleanup = function () {
delete window.foo;
delete window.cleanup;
};
// unload all resources
cleanup();
另一种方法是为片段使用模块化对象结构,然后自行清理。这涉及稍高的开销,但可能是值得的,因为它使代码更容易阅读和维护:
// creates the object using the second parameter as prototype.
// .create() is used as constructor
GlobalModuleHandlerThingy.addModule('my_module', {
create: function () {
this.foo = 'bar';
return this;
},
foo: null,
destroy: function () {
// unload events, etc.
}
});
GlobalModuleHandlerThingy.getModule('my_module').foo; // => bar
GlobalModuleHandlerThingy.unloadModule('my_module'); // calls .destroy() on the module and removes it.
答案 2 :(得分:4)
也许您需要考虑有条件地加载它而不是有条件地卸载它......
答案 3 :(得分:2)
如果您需要卸载特定对象,则相当简单:只需将其设置为{}
ie:myobj = {};
因此,如果您知道在特定包含中创建了哪些对象,那么它就不会很难。
另一方面,如果您不知道在特定包含中创建了哪些对象,则无法找到机制 - 您不能要求Javascript告诉您在特定包含中定义了什么。
但是,我会说,如果你不知道在特定的javascript文件中加载了什么对象,你可能不会在加载它时给自己任何好处(你应该总是有一个合理的想法,代码在做什么)你的网站),或试图手动卸载它(如果你不知道它做了什么,这意味着它的第三方包括,这意味着手动取消它可能会破坏它。)
答案 4 :(得分:0)
我正在研究类似的事情并认为我会发布我的发现
将您的东西包装在js文件中的全局命名空间中,以便可以轻松删除它,即 var stuff = {blabla:1,method:function(){}};
当你需要摆脱它时,只需设置stuff = {},或者甚至是
***如果您使用requirejs - require js remove definition to force reload
注意:只要您不在其他任何地方引用命名空间内的模块,GC就会收集所有内容,您就可以开始使用了。
答案 5 :(得分:0)
我想到了这个诀窍。我想知道这里几天找到答案,我只是意识到一个完美的技巧,而不试图卸载Java脚本。您只需要在
currentPage
页面的java脚本中创建一个全局变量,如main
,当您加载页面时,将页面名称指定给currentPage
。然后在每个其他.js
文件中使用$('document').ajaxComplete()
$('document').ready()
{}} {}} {}} {}} {}} {{}}将其设置为检查$('document').ajaxComplete()
变量等于新的页面名称。在if语句中添加所有其他事件。我不太懂英语所以请检查我的代码。这是我的第一个答案,如果我犯了一些错误就很抱歉。
main.html中
currentPage
main.js
<body>
<div id='container></div>
<button id="load1">
<button id="load1">
</body>
我的所有页面脚本和样式都在单独的文件夹视图中,js,css。
page1.html
var currentPage = "";
$(document).ready(function () {
$('#load1').click(function () {
loadSource('page1', 'body');
});
$('#load2').click(function () {
loadSource('page2', 'body');
});
});
function loadSource( page, element){
currentPage = page;
$('#container').load('views/' + page + '.php', element);
$.getScript('js/' + page + '.js');
$('#css').prop('disabled', true).remove();
$('head').append('<link rel="stylesheet" href="css/' + page + '.css" type="text/css" />');
}
page1.js
<body>
<button id="test1">
<button id="test2">
</body>
page2.html
$(document).ajaxComplete(function () {
if(currentPage == 'page1'){
/*$('#test1').click(function () {
console.log('page1');
});*/
$('#test2').click(function () {
console.log('page1');
});
}
});
page2.js
<body>
<button id="test1">
<button id="test2">
</body>
我在每个脚本中注释了一个按钮,以检查该按钮是否仍然具有旧脚本的影响。
答案 6 :(得分:0)
您可以将它们设置为null
function fnc1 (){
}
window.fnc1 = null
//or
window["fnc1"] = null