JS闭包

变量作用域

  • 局部变量
  • 全局变量
  • 当函数执行完毕,本作用域内的局部变量就会自动销毁

闭包的定义

指有权访问另一个函数作用域中变量的函数

闭包的作用

在函数a执行完毕并返回后,闭包使得Js的垃圾回收机不会回收a所占用的资源,因为a的内部函数b需要依赖a中的变量,从而延伸了变量的作用范围。

demo
function fn() {
            var num = 10;
            return function fun() {
                console.log(num);
            };
        }
        //fn外面的作用域访问fn()内部的局部变量
        fn()();//10

闭包的例子

获取ul中li的索引号
  • 最初的方法
var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            lis[i].setAttribute('index', i);
            lis[i].addEventListener('click', function () {
                console.log(this.getAttribute('index'));
            })
        }//在循环的同时给每个li添加自定义属性index,需要时再读取属性值
  • 利用闭包
for (var i = 0; i < lis.length; i++) {
            //创建了4个立即执行函数
            (function (num) {
                lis[num].onclick = function () {
                    console.log(num);
                }func
            })(i)
        }

这里面的闭包指的是匿名函数,通过(i)把值保存到了num中。每个点击事件都有一个局部变量num,num保存的是相应的i值。

  • 错误写法
for (var i = 0; i < lis.length; i++) {
            lis[i].addEventListener('click', function () {
                console.log(i);
            })
        }//无论点击哪个li都输出4

每个li标签的onclick事件执行时,本身onclick绑定的function的作用域中没有变量i,i为undefined,则解析引擎会寻找父级作用域,发现父级作用域中有i,且for循环绑定事件结束后,i已经赋值为4,所以每个li标签的onclick事件执行时,log的都是父作用域中的i,也就是4。

经典例子
function fn() {
            var num = 3;
            return function () {
                var n = 0;
                console.log(++n);
                console.log(++num);
            }
        }
        fn()();// 1 4
        fn()();//1 4
        
        var f1 = fn();
        f1();//1 4
        f1();//1 5

        

直接调用fn函数,此时fn执行完后,就连同它的变量num一同销毁,但是如果将fn的返回值赋给f1,这时候相当于f1=function(){var n = 0};并且匿名函数内部引用这fn里面的变量num,所以变量num无法被销毁,而变量n在调用完后会销毁,在每次调用时新建,于是最后只剩下num,所以再次调用时num是在4的基础上+1。

定时器中的闭包函数

		//3秒后同时打印所有li元素的内容
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function (a) {
                setTimeout(function () {
                    console.log(lis[a].innerHTML);
                }, 3000)
            })(i);
        }
        
        //每隔3秒打印一个li元素的内容
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function (a) {
                setTimeout(function () {
                    console.log(lis[a].innerHTML);
                }, a*3000)
            })(i);
        }

闭包的缺点

因为闭包会使得Js的垃圾回收机不会回收占用的资源,滥用闭包会造成内存泄露,所以在必要时,我们要及时释放这个闭包函数

Let的出现

将上面的错误写法中的var改为let,let会产生块级作用域

for (let i = 0; i < lis.length; i++) {
            lis[i].addEventListener('click', function () {
                console.log(i);
            })
        }//点击li输出相应的索引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值