在闭包中编写js有很多好处,最大的好处就是可以一直保存上下文,因此许多js插件都是在闭包中编写的。例如:
var a = (function() {
var content = $("#content");
var dis = function() {
console.log(content);
content.css("background-color", "yellow");
};
return {
"dis": dis
};
})();
上述写法就是在闭包中封装了对于DOM元素的操作,在闭包一开始就把所有有可能涉及的DOM元素”#content”获取到并复制给闭包内的局部变量,当执行a.dis()时会在控制台输出该DOM元素并修改背景色为黄色。很好很规范的写法是不是?
但是在闭包中如果涉及到DOM元素的操作,并且该DOM元素在使用过程中有删除和重建的操作,上述的写法就会出问题,比如:页面上增加对于$(“#content”)[0]元素的删除和重建操作,a.dis()还能正确执行,修改div的背景色吗?
全部代码如下:
<html>
<head>
<title>DOM操作测试</title>
<meta charset="utf-8">
<script type="text/javascript" src="http://cdn.bootcss.com/jquery/1.11.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
var a = (function() {
var content = $("#content");
dis = function() {
console.log(content[0]);
content.css("background-color", "yellow");
};
return {
"dis": dis
};
})();
$("#btn2").click(function() {
$("#main").empty();
});
$("#btn3").click(function() {
$("#main").html('<div id="content" style="width:100px;height:100px;background:black"></div>');
});
$("#btn1").click(function() {
a.dis();
});
})
</script>
</head>
<body class="body">
<div id="main">
<div id="content" style="width:100px;height:100px;background:black"></div>
</div>
<input id="btn1" type="button" value="修改DOM" />
<input id="btn2" type="button" value="删除DOM" />
<input id="btn3" type="button" value="增加DOM" />
</body>
</html>
测试过程:
- 点击“修改DOM”,DIV背景变为黄色
- 点击“删除DOM”,DIV被删除
- 点击“增加DOM”,DIV又被加上
- 再次点击“修改DOM”,DIV背景未变化,但是控制台中a.dis()仍然能输出先前记录下的DOM元素
结论:闭包内被预先定义的DOM元素变量无法在DOM元素变化时及时更新,其相当于只存储了该DOM对象当时的快照,当DOM元素变化(删除后重建)时无法正确的指向最新的DOM元素。
上述测试标明,在闭包中涉及的DOM元素的操作需要注意,DOM对象如果是在闭包内使用局部变量预先定义好,而不是每次使用时用jquery来获取,那就需要注意这个DOM元素变化可能带来的风险,否则会发生无法预知的错误。
建议不要使用闭包级别的局部变量来存储DOM对象,而是在闭包的方法内使用局部变量来存储DOM对象,这样可以避免该风险的发生。
修改后的闭包代码:
var a = (function() {
dis = function() {
var content = $("#content");
console.log(content);
content.css("background-color", "yellow");
};
return {
"dis": dis
};
})();