闭包与立即执行函数

首先先说立即执行函数,从名字就可以看出来立即执行函数的特点,在JavaScript中用function表示函数声明,如果在函数声明后面加上括号调用是不允许的
 
function f() {}(); //SyntaxError: Unexpected token ) 
这里会报错,为了避免错误,我们在函数声明前面添加标识符让引擎认为这是一个表达式,所以下面写法都是正确的。

注意:这里因为立即执行函数是表达式,所以“;”不要忘记省略了
(function() {})();
(function() {}());
~function() {}();
!function() {}();
+function() {}();
-function() {}();
//...
不过最常用的还是上面两种,立即执行函数有什么用呢?
  • 第一点可以避免污染变量名,立即执行函数不用给函数名起名称。
  • 第二形成单独作用域,让外部无法访问到。

什么是闭包?

正常一点的:能让函数记住并能访问所在的作用域称为闭包。

文艺一些的:闭包就是函数内部与函数外部搭建起来的一座桥梁。

闭包的特点: 从定义可以看到,闭包会记住所在的环境,也就是说闭包会一直存在内存之中,所以不应该滥用闭包,在调用完成后手动释放他。

下面是一个例子

function foo() { 
    function fn(name) { 
        return name; 
}     
    return fn; 
}
var a = foo(); a(); 

这里是一个闭包,在我们调用a()结束后,因为foo内部的fn是a的引用,所以这个闭包会一直存在。

为什么要使用闭包? 事实上,我们在很多情况下不知不觉的都在使用闭包,就拿作用域来说,函数作用域在外部是无法正常访问到的,但是可以通过在内部定义一个函数返回,在外部拿到想要的变量。

扫描二维码关注公众号,回复: 3052209 查看本文章
function foo() {
    var a = 10;
    function fn() {
        console.log(a);
    }
    return fn;
}
var a = 20;
var as = foo();
as(); //10

上面就是一个闭包使用的例子,还有在循环中

for (var i = 0; i < 5; i++) {
    setTimeout(() => {
    console.log(i);
    }, i * 1000);
}

 猜猜看这里输出的是什么? 答案是5,因为全局环境下就只有一个i,在循环结束后i变成了5,setTimeout是异步调用,所以这里输出的全部是5。

如果想让他正确输出应该怎么做?

这里实现方式有多种,但是这里讨论的是闭包实现,可以在循环内部,嵌套一个立即执行函数。

for (var i = 0; i < 5; i++) {
    (function (name) {
        setTimeout(() => {
            console.log(name);
        }, i * 1000);
    })(i);
}

这里每次循环都会创建一个新的作用域,因为立即执行函数也是函数可以传递参数给他。

闭包的应用 闭包主要的用途有两种,

  • 第一种作为获取函数返回值使用,在上面已经举例说明了;
  • 第二种就是作为模块来使用,暴露最少的接口。

下面是一个应用的例子

var fn = function() {
    var a = {};
    function add(name, fn) {
        a[name] = fn;
    }
    function get(name) {
        return a[name]();
    }
    return {
        add: add,
        get: get
    }
};
var a = fn();
a.add('fn', function() {
console.log('hi');
});
a.get('fn');

 

 

猜你喜欢

转载自www.cnblogs.com/boses/p/9585547.html