深入理解JavaScript闭包以及应用场景

一、什么是闭包?

  • 闭包就是一个函数,它处于另一个函数中,并且可以访问它的外部函数中的变量。
function fun(){
    var n=0;
    return function(){ //这就是一个闭包,它可以使用变量n
    	n++; 
    	console.log("n="+n);
    }
}
var f=fun();
 f();  //输出:n=1
 f(); //输出:n=2

二、闭包有什么作用?

  • 访问外部函数的变量。
  • 防止外部函数执行完之后,变量被销毁。
  • 加强封装性。

三、闭包的缺点?

  • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,很容易造成内存泄漏。

四、闭包的应用场景

1. 通过循环给页面上多个dom节点绑定事件,点击编号为几的节点则弹出它对应的编号

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

如果不使用闭包:

for(var i = 0; i < list.length; i++) {
  list[i].addEventListener('click', function(){
      alert(i)
    }, true)
}

由于点击事件是异步触发的,当事件被触发时,for循环以及结束了,此时变量i的值已经是5!所以当点击事件顺着作用域链从内向外查找变量i时,找到的值总是5,所以无论点击哪一项都会弹出5。
下面用闭包改写:

var list = document.getElementsByTagName('li')
for(var i = 0; i < list.length; i++) {
  list[i].addEventListener('click', function(i){
    return function() {
      alert(i+1)
      console.log(i+1)
    }
  }(i), true)
}

改成闭包之后,每次循环的i值都被封闭起来,这样在函数执行时,会查找定义时的作用域链,这个作用域链里的i值是在每次循环中都被保留的,因此点击不同的li会alert出不同编号。

2. setTimeout

原生的setTimeout传递的第一个函数是不能带参数的:

setTimeout(fun(),1000);

因此,闭包就派上用场了:

function fun(num){
  var age = num;
  return function(){
       console.log(age);
  }
}

var getAge = fun(200);//传入需要的参数,得到函数(闭包)的引用
var age = setTimeout(getAge,1000);//正确输出

3. 使用闭包访问私有变量

function Fun(){
  var name = 'tom';
  
  this.getName = function (){
    return name;
  }
}

var fun = new Fun(); 
console.log(fun.name);//输出undefined,在外部无法直接访问name
console.log(fun.getName());//输出tom

最后,觉得一位大佬说的很好:

闭包这东西,举个不恰当的例子:就像Java里常说的设计模式。
很多人痴迷于各种设计模式,就想方设法硬是用到工作中,然后就觉得高大上了,而不管合适不合适。实际上,那些前人总结出来的设计模式,确实是精华,确实值得学习。但是不管合适不合适、需要不需要地直接拿来用是不对的。我们应该吸收里面的思想而不是形式,等你代码写多了,经验多了,就会不经意地用上,甚至自创出之前没有但是更适合你自己的模式。

闭包也一样,闭包只是个术语而已,我们应该去了解它形成的原理,它的形成背后的知识点,比如作用域链、变量解析、词法环境等等,从而真正理解为什么出现闭包这种现象。而不是觉得它高大就必须把它用到工作中。等你代码写多了,涉猎范围广了,自然会不知不觉用上它。真的,到那时候,很可能你代码里出现了闭包,但是你却没有意识到。

发布了54 篇原创文章 · 获赞 4 · 访问量 3138
App 阅读领勋章
微信扫码 下载APP
阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览