闭包

MDN解释:
闭包是使用被作用域封闭的变量,函数,闭包等执行的一个函数的作用域。通常我们用和其相应的函数来指代这些作用域。(可以独立访问数据的函数)
首先这是个错误的说法:闭包就是 在一个作用域中可以访问另一个作用域的变量。
一个函数嵌套一个函数,在嵌套的函数中访问到了外部函数(作用域)中的变量或者函数,就会发生闭包现象
例子:

function fn(){
	var n= 10;
	return n;
}
fn();
// 注意我们在看是否产生闭包的时候,最好通过断点调试的方式来查看当前是否产生闭包Closure (fn)。通过调试,没有出现Closure 的字眼。说明没有发生闭包。

当这个函数结束的时候,就会立即释放函数的作用域,作用域中的全局变量n=10也就被销毁了

function fn() {
  var n = 10;
  return function() {
    return n;
  };
}
var f = fn()// 因为fn的返回值是一个函数  所以必须用一个函数来接收
console.log(f());

在这个函数中,函数在执行完毕之后,返回了一个函数,而在返回的函数中又访问了父作用域中的一个变量。所以当我们在调用完函数fn()的时候,函数的作用域并没有被销毁。因为变量n 还有人f()会去访问。所以闭包延展了函数的作用域

闭包的应用

需求,在点击页面中的所有li的时候,输出当前li的索引

    <ul id="heros">
      <li>01</li>
      <li>02</li>
      <li>03</li>
      <li>04</li>
      <li>05</li>
    </ul>
    <script>
      var heros = document.getElementById("heros");
      var list = heros.children;
      //   console.log(list.length)//5
      for (var i = 0; i < list.length; i++) {
        var li = list[i];
        li.onclick = function() {
          console.log(i);
        };
      }
    </script>

以上的代码结果并不符合需求,不论点击哪一个li 都显示的是5。而不是对应的索引数。
我们知道js的执行机制:代码从上往下执行。遇到定时器或者函数的时候,先把这些复杂类型的数据放到栈中保存,等到其他的代码都执行完毕的时候,才会将栈中的代码push出,一件一件的进行执行。li的点击事件在一开始的时候并没有执行,而是在用户点击的时候才执行。等待执行点击事件的时候,循环早已经执行完了。所以最后i的值是5,i是全局变量。解决方法如下:

//方式一:
      var heros = document.getElementById("heros");
      var list = heros.children;
      for (var i = 0; i < list.length; i++) {
        var li = list[i];
        li.index = i;
        li.onclick = function() {
          console.log(this.index);
        };
      }
// 方式二:
      var heros = document.getElementById("heros");
      var list = heros.children;
      for (var i = 0; i < list.length; i++) {
        var li = list[i];
		(function(i){ //自调用函数
			li.onclick = function() {
          		console.log(i);
        	};
		})(i)
      }
      // 方法二用到了闭包。但是闭包延展了函数的作用域。会造成内存泄漏。一些内存不能用完就释放,会造成卡顿现象。所以在使用完闭包的时候要即使的清空因闭包产生的内存
    // 再看一个例子
    for (var i = 0; i <3; i++) {
		(function(i){ 
			setTimeout(function(){
				console.log(i)
			},0)
		})(i)
      }
      // 每次循环都开启一个作用域,将当前循环的变量i保存在每个作用域中,再次访问的时候就会访问到当前循环的的作用域中,从而就把当前的循环变量i打印出来了。
    <ul id="heros">
      <li size="12" >01</li>
      <li size="14" >02</li>
      <li size="16" >03</li>
      <li size="18" >04</li>
      <li size="20" >05</li>
    </ul>
    <script>
		function makeFun(size ){
			return function(){
				document.body.style.fontSize = size + 'px';
			}
		}
		var heros = document.getElementById('heros')
		var list = heros.children;
		for(var i = 0; i< list.length;i++){
			var li = list[i]
			var size = btn.getAttribute('size')
			li.onclick = makeFun(size)
		}
	</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值