闭包的前世今生-03-闭包与即时函数

350 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

闭包与即时函数

大家见过这种样式的代码么?


(function() {
    alert();
})()

这个样式的代码就是我们今天的主角:立即执行函数(IIFE)

IIFE:Immediately-Invoked Function Expressions

  • 声明一个函数

  • 立即调用这个函数

  • 语句结束后就销毁(语句结束没有引用了)

实际上,闭包与立即执行函数并没有什么关系,但是立即执行函数经常可以和闭包结合起来发挥巨大的作用。

常见作用

作用一: 创建临时独立的作用域

假设我们需要一个非常大型的生活工具项目,需要一个有人打扰就自动累计被打扰的时间,每当我们潜心修行却被打扰的时候,都需要运行一下这个系统,一秒一秒的积攒我们的怒火,要怎么实现呢?

首先我们可以创建一个内部变量来自动保存一下累加的次数,其次设计一个setIntaval来度秒如年的运行程序。

那么我们可以用下面的方案:


let cnt = 0

setIntaval(() => console.log(++cnt), 1000)

但是这个方案有个问题,我这个程序太大型了,没办法保证我最顶层的cnt不会污染其他的功能,因此我们需要换一种写法,使用下面的方案。

    const addTime = () => {
        setIntaval(
            (function() {
                let n = 0
                return function(){console.log(++cnt)
            }
        })(), 1000)
    }

这个方案的好处是,当我们循环被清理掉之后,对应的 cnt 变量也会被清理掉。

作用二:解决变量名的冲突问题

利用参数优先全局变量的规则,可以函数内部的小环境限制作用域变量名称。

比如Jquery的全局符号,如果其他库也使用了符号,如果其他库也使用了符号的话,就会造成函数名冲突。

假设我们有大量代码存在使用这个同名方法的情况但是却依然要使用Jquery,

我们这时候可以使用自执行函数使用如下方法解决此问题。

(function(){})(Jquery)

作用三:使用简洁变量名

类似wich这个功能


const data = {
    ab: {
        cd: 0
    }
}

(function(a){
    console.log(a);
})(data.ab.cd)

作用四:处理循环陷阱

什么是循环陷阱呢?

看看下面的代码

const arr = [];
for(var i = 0; i < 5; i++) {
    arr.push(function() {
        return console.log(i)
    })
};

arr[0]();
arr[1]();

解决方案

const arr = [];
for(var i = 0; i < 5; i++) {
    (function(n) {
        arr.push(function() {
            return console.log(n)
        })
    })(i)
};

arr[0]();
arr[1]();

末尾指路

这是我JS闭包系列的文章合集

闭包的前世今生-01-闭包与作用域链

闭包的前世今生-02-惰性函数、偏应用函数与柯里化

闭包的前世今生-03-闭包与即时函数

闭包的前世今生-04-闭包与类库封装、模块化(Webpack)