详解 JavaScript 中的闭包

详解 JavaScript 中的闭包

一、概念

JavaScript 中有作用域和作用域链的概念,变量的访问只能在作用域内,如果该作用域内找不到,就向上查找父作用域,直到找到为止。那么如何在外层也能访问到作用域内的变量,就是今天的登场主角“闭包”。闭包可以通过函数作用域内返回另一个函数来达到此目的。在一般的开发项目中,可能闭包用得并不多,但是在框架工具源码里,闭包的使用遍地可见。

二、特点

  • 由于闭包内部保存着外部引用的变量,不会被垃圾回收机制回收,所以会一直保存在内存中,从而消耗内存。在 IE 中可能导致内存泄漏,所以在退出函数前,将不使用的变量全部删除。
  • 使用闭包模拟私有属性或方法时,不能随意改变父函数作用域内变量的值。
  • 使用闭包时返回函数不要引用任何循环变量,或者在循环中会发生变化的变量。可以创建一闭包,用函数的参数值绑定循环变量当前的值,这样,无论循环变量如何改变,绑定到函数的参数不会变。

三、应用

  1. 在外层访问或改变函数作用域内变量;
function person() {
        var x = 3;
        return function () {
            x++;
            return x;
        }
};
 var m= person();
 console.log(m());//4
 console.log(m());//5
 console.log(m());//6					
  1. 将函数作为参数调用匿名函数;
(function person(f) {
var x= 10;
 f(x);
})(person);
function person(n){
 console.log(n)//10
};		
  1. 用闭包模拟私有方法
var person = (function(){
var index = 0;
var increase  = function(){
     index++;
};
return {
	get:function(){
	   return index;
	},
	increase:function(){
	    increase ();
	}
 }
})();
console.log(person.get());//0
person.increase();
console.log(person.get());//1
  1. 五种方法解决循环引用问题
    本文只列出方法,如果想要了解每个方法的解析原理,可参考文章《点击每个兄弟节点获取对应节点下标的五种方案详解》
//要求:点击每个 li 打印出对应的下标。
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
var lis=document.getElementsByTagName('li');
for(var i=0;i<=lis.length-1;i++){
    lis[i].onclick = function () {
         console.log(i)
   };
}
//现象:不论点击哪一个 li 都打印出 lis.length(有几个li就打印出几)。
</script>
//解决方案一:使用 let,将以上循环脚本中的 var 改成 let 即可
for(let i=0;i<=lis.length-1;i++){
    lis[i].onclick = function () {
         console.log(i)
   };
}
//解决方案二:给 DOM 属性赋值。
for(var i=0;i<=lis.length-1;i++){
    lis[i].id = i;
    lis[i].onclick = function () {
          console.log(this.id)
   };
}
//解决方案三:使用传参闭包1。
for(var i=0;i<=lis.length-1;i++){
    lis[i].onclick = (function (m) {
        return function(){
          console.log(m)
       }
   })(i);
}
//解决方案四:使用传参闭包2。
for(var i=0;i<=lis.length-1;i++){
    (function(m){
        lis[i].onclick = function () {
            console.log(m)
        };
    })(i)
}
//解决方案五:使用不传参闭包+变量关联。
for(var i=0;i<=lis.length-1;i++){
    (function(){
        var id = i;
        lis[i].onclick = function () {
            console.log(id)
        };
    })()
}

四、意义

  • 可在外层访问或改变作用域内的变量;
  • 可使用闭包模拟私有属性或方法;
  • 可使用闭包解决循环引用的问题。
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值