JS闭包

问题起源

一个函数执行后,内部的变量会被回收(销毁),有没有一种办法能让这个变量继续存在呢?

几个名词

Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

变量回收是指在一些编程语言中,函数内的局部变量只在函数执行期间存活。

一旦 makeFunc() 函数执行完毕,你可能觉得 name 变量就不能存在了。闭包的最大特性就是,如果里函数引用了父级函数的某个变量,那这个变量就能享受和全局变量一样的特权,不会被回收!除非你关闭页面或浏览器!

function makeFunc() {
  var name = 'Mozilla';
  function displayName() {
    alert(name);
  }
  return displayName;
}
var myFunc = makeFunc();
myFunc();

闭包原理

  • 闭包是由函数以及该函数的词法环境组合而成,这个环境包含了这个闭包创建时所能访问的所有局部变量

  • returen一个函数,再把这个函数当做回调函数赋给事件(事件执行时才真正触发)

  • 变量可以是父级函数的属性,也可以是父级函数所接受的参数

  • 两大作用:读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中

  • 同一个闭包机制可以创建多个闭包函数出来,它们彼此没有联系,都是独立的,并且每个闭包函数可以保存自己个性化的信息。

  • 以下三个闭包彼此独立、没有联系:

 function f1(num){
        function f2(){
            alert('数字:'+num);
        }
        return f2;
    }
    var fa = f1(10);
    var fb = f1(20);
    var fc = f1(30);
    fa();   //数字:10
    fb();   //数字:20
    fc();   //数字:30

MDN的例子

这个例子是通过点击三个按钮来动态的改变网页文本的大小,不过这个例子有点鸡肋,有种为了写闭包而刻意写成这样的感觉。

<body>
    <p>Some paragraph text</p>
    <h1>some heading 1 text</h1>

    <a href="#" id="size-12">12</a>
    <a href="#" id="size-16">16</a>
    
    // onclick在html中只能用 func()的形式
    <button id="button" onclick="test(5)">点击</button>
    
    <script>
	    function makeSizer(size) {
	        return function() {
	            document.body.style.fontSize = size + 'px';
	        };
	    }
	
	    var size12 = makeSizer(16);
	    var size16 = makeSizer(24);
	
	    document.getElementById('size-12').onclick = size12;
	    document.getElementById('size-16').onclick = size16;
	
	
	    function test(x){ 
	        console.log('我是' + x )
	    }
	    // onclick在js代码中只能传入事件名func,在html中只能用 func()的形式
	    // document.getElementById('button').onclick = test;

    </script>
</body>

一个常见问题

for(var i=0;i<10;i++){
    setTimeout(function(){
        console.log(i)//10个10
    },1000)
}

解决办法:

  • 用let替换var,三个环境和一个环境
  • 匿名函数

用匿名函数包裹原函数后形成了一个闭包,这保证了 每个 i 在当时块级作用域中的环境被保存下来,所以每次输出都不同

 for (var i = 0; i < helpText.length; i++) {
    (function() {
       var item = helpText[i];
       document.getElementById(item.id).onfocus = function() {
         showHelp(item.help);
       }
    })(); // 立即调用绑定函数,使用正确的值绑定到事件上;而不是使用循环结束的值
  }

注意

闭包带来的性能问题,过多的使用闭包会导致占用内存太多

参考:

https://developer.mozilla.org/zhCN/docs/Web/JavaScript/Closures
https://blog.csdn.net/coder_vader/article/details/78839686
https://juejin.im/entry/58f424d5570c3500563d7541
https://zhuanlan.zhihu.com/p/22486908

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值