//闭包
var myObjectNew = (function () {
var value = 0;
return {
increment: function (inc) {
value += typeof inc === 'number' ? inc : 1;
},
getValue: function () {
return value;
}
}
}());
var quo = function (status) {
return {
get_status: function () {
return status;
}
}
};
var myQuoNew = quo('amazed');
console.log('status=' + myQuoNew.get_status());
当我们调用quo时,它返回包含get_status方法的一个新对象。该对象的一个引用保存在myQuo中。即使quo已经返回了,但get_status方法仍然享有访问quo对象的status属性的特权。get_status方法并不是访问该参数的一个副本,它访问的就是该参数本身。这是可能的,因为该函数可以访问它被创建时所处的上下文环境。这被称为闭包。
理解内部函数能访问外部函数的实际变量而无须复制是很重要的
//糟糕的例子
//构造一个函数,用错误的方式给一个数组中的节点设置事件处理程序。
//当点击一个节点时,按照预期,应该弹出一个对话框显示节点的序号。
//但它总是会显示节点的数目
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i++) {
nodes[i].onclick = function (e) {
alert(i);
}
}
};
add_the_handlers函数的本意是想传递给每个处理器一个唯一值(i)。但它未能达到目的,因为事件处理器函数绑定了变量i本身,而不是函数在构造时的变量i的值。
//改良后的例子
var add_the_handlers_new = function (nodes) {
var helper = function (i) {
return function (e) {
alert(i);
}
}
var i;
for (i = 0; i < nodes.length; i++) {
nodes[i].onclick = helper(i + 1);
}
};
避免在循环体中创建函数,它可能只会带来无谓的计算,还会引起混淆,正如上面那个糟糕的例子。我们可以先在循环之外创建一个辅助函数,让这个辅助函数再返回一个绑定了当前i值的函数,这样就不会导致混淆了。
复制下面的文件到html文件里即可运行查看效果!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
.button{
font-family:"Arial";border:0;
vertical-align:middle;margin:8px;line-height:18px;font-size:18px;
140px;height:36px;line-height:18px;font-size:18px;
}
</style>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
</head>
<body>
<div style="margin-top: 20px">
<input type="button" class="button" value="按钮1">
<input type="button" class="button" value="按钮2">
<input type="button" class="button" value="按钮3">
<input type="button" class="button" value="按钮4">
<input type="button" class="button" value="按钮5">
</div>
<script type="text/javascript">
var add_the_handlers_new = function (nodes) {
var helper = function (i) {
return function (e) {
alert(i);
}
}
var i;
for (i = 0; i < nodes.length; i++) {
nodes[i].onclick = helper(i + 1);
}
};
add_the_handlers_new($('.button'));
</script>
</body>
</html>
闭包的好处有:
1.缓存
2.面向对象中的对象
3.实现封装,防止变量跑到外层作用域中,发生命名冲突
4.匿名自执行函数,匿名自执行函数可以减小内存消耗
闭包的坏处:
1.内存消耗
通常来说,函数的活动对象会随着执行期上下文一起销毁,但是,由于闭包引用另外一个函数的活动对象,因此这个活动对象无法
被销毁,这意味着,闭包比一般的函数需要更多的内存消耗。尤其在IE浏览器中需要关注。由于IE使用非原生javascript对象实现
DOM对象,因此闭包会导致内存泄露问题。
2.性能问题
使用闭包时,会涉及到跨作用域访问,每次访问都会导致性能损失。
因此在脚本中,最好小心使用闭包,它同时会涉及到内存和速度问题。不过我们可以通过把跨作用域变量存储在局部变量中,然后直
接访问局部变量,来减轻对执行速度的影响。
内存泄露
1.定义:一块被分配的内存既不能使用,也不能回收。从而影响性能,甚至导致程序崩溃。
2.起因:JavaScript的垃圾自动回收机制会按一定的策略找出那些不再继续使用的变量,释放其占有的内存。然而由于一些原因
导致在这种机制下内存管理器不能正确解读javascript变量的生命周期,从而没有释放其内存,而也没有再被使用。循环引用是
导致以上情况的主要原因之一。
解决方法:常用的解决方法就是在JavaScript代码段运行完之时将形成循环引用的JavaScript对象手动设置为空,切断引用。
附加:一个朋友给了实现这个功能又不用闭包的方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
.button{
font-family:"Arial";border:0;
vertical-align:middle;margin:8px;line-height:18px;font-size:18px;
140px;height:36px;line-height:18px;font-size:18px;
}
</style>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
</head>
<body>
<div style="margin-top: 20px">
<input type="button" class="button" value="按钮1">
<input type="button" class="button" value="按钮2">
<input type="button" class="button" value="按钮3">
<input type="button" class="button" value="按钮4">
<input type="button" class="button" value="按钮5">
</div>
<script type="text/javascript">
var add_the_handlers_new = function (nodes) {
for (var i = 0; i < nodes.length; i++) {
nodes[i].onclick = function() {
var index = $(this).index();
alert(index + 1);
};
}
};
add_the_handlers_new($('.button'));
</script>
</body>
</html>
附加二:如果用ES6也可以
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
.button{
font-family:"Arial";border:0;
vertical-align:middle;margin:8px;line-height:18px;font-size:18px;
140px;height:36px;line-height:18px;font-size:18px;
}
</style>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
</head>
<body>
<div style="margin-top: 20px">
<input type="button" class="button" value="按钮1">
<input type="button" class="button" value="按钮2">
<input type="button" class="button" value="按钮3">
<input type="button" class="button" value="按钮4">
<input type="button" class="button" value="按钮5">
</div>
<script type="text/javascript">
var add_the_handlers_new = function (nodes) {
for (let i = 0; i < nodes.length; i++) {
nodes[i].onclick = function() {
alert(i + 1);
};
}
};
add_the_handlers_new($('.button'));
</script>
</body>
</html>
备注:欢迎加入web前端求职招聘qq群:668352707