浅谈js闭包

简介

闭包是啥,用一句通俗的话来说就是能够读取函数内部局部变量的函数。闭包在一个函数内部定义一个新的函数,在执行的时候,会将这个函数返回,也可能是返回一个对象。闭包为啥会出现呢,它其实是js作用域链的特性而产生的。我们在函数内部是可以直接访问函数外部的全局变量的,但是我们在函数的外部是无法直接获取到函数内部的局部变量的,如果我们想在函数外部获取函数内部的局部变量,那么就要用到闭包。

函数内部可以直接访问函数函数外部的全局变量

var num = 66
function fn1() {
    console.log(num)
}
fn1()   // 66

函数外部不可以访问函数内部的局部变量

function fn2() {
    var kk = 88 // 这里一定要用var来定义,如果不用的话,kk会变量提升变成全局变量
}
console.log(kk) // Uncaught ReferenceError: kk is not defined

闭包的作用

1、读取函数内部的局部变量

function fn() {
    var a = 5
    return function() {
        return a
    }
}
console.log(fn()()) // 5

2、让局部变量的值始终保存在内存中

function num() {
    var num = 100
    add = function() {
        num++
    }
    function getNum() {
        return num
    }
    return getNum
}
var result = num()
console.log(result())   // 100
add()
console.log(result())   // 101

为啥说可以让局部变量始终保存在内存中呢?我们分析一下,首先getNum函数被赋予一个全局变量,这就导致getNum函数在内存中不会被垃圾回收机制清理掉,又因为getNum函数是依赖于num函数的,所以num函数也不会被垃圾回收机制清理掉,既然num函数不会被清理掉,那么num局部变量也就一直存在于内存中了。所以就会出现,你调用了两次num函数一次add,一次打印100,一次打印101。
这里有个要注意的点,add变量没有用var定义,所以他是全局变量,所以函数外面可以直接访问

闭包的缺点

看上面的例子,函数num始终在栈中得不到释放,就会长时间占用内存,就会造成内存泄露,内存泄露多了会造成内存溢出

使用场景

1、setTimeout传参

原生的setTimeout传递的第一个函数是不能带参数的,通过闭包可以实现带参

function fn1(name) {
    function fn2() {
        console.log(name)
    }
    return fn2
}
var fun = fn1('张三')
setTimeout(fun,1000)    // 一秒钟之后打印张三

2、回调

定义行为,然后把它关联到某个用户事件上(点击或者按键)。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。

<body>
    <a href="#" id="size-12">12</a>
    <a href="#" id="size-20">20</a>
    <a href="#" id="size-30">30</a>

    <script type="text/javascript">
        function changeSize(size) {
            return function() {
                document.body.style.fontSize = size + 'px';
            }
        }

        document.getElementById('size-12').onclick = changeSize(12);
        document.getElementById('size-20').onclick = changeSize(20);
        document.getElementById('size-30').onclick = changeSize(30);
    </script>
</body>

3、函数防抖

在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。

/*
    * fn [function] 需要防抖的函数
    * delay [number] 毫秒,防抖期限值
*/
function debounce(fn,delay) {
    let timer = null
    return function() {
        if(timer) {
            // 说明在一个计时过程中,又触发了相同的事件,所以需要清除定时器,重新定时
            clearTimeout(timer)
            timer = setTimeout(fn,delay)
        }else {
            timer = setTimeout(fn,delay)
        }
    }
}

4、循环赋值

for(i=0;i<10;i++) {
    (function(j){
        console.log(j*10)
    })(i)
}
// 0 10 20 30 40 50 60 70 80 90

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值