再来了解下闭包吧

我心飞翔 分类:javascript

这是我参与更文挑战的第5天,活动详情查看:更文挑战

作为一个前端人,不管是在js学习之初还是在工作中都会遇到闭包,更甚者你已经在不经意间写了很多闭包。而闭包又是前端面试中几乎避不开的一个知识点。下面我们就来一起了解下闭包吧。

闭包的概念

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。《MDN》
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。《你不知道的javaScript》

上述两个文档中都很好的阐述了闭包的概念,我们可以知道闭包是一种现象,在js中由于有顶层对象的存在,可以说是每当创建一个函数的时候,闭包就会在函数创建的同时被一同创建出来。

闭包让你可以在一个内层函数中访问到其外层函数的作用域。

var windowName = '全局的name'
function makeFunc() {
    var name = "Mozilla";
    console.log(windowName)
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();
 

上述代码中,执行makeFunc函数将其内部定义的displayName函数作为返回值返回,并赋值给myFunc变量,最后执行myFunc,从而输出了定义在makeFunc函数内部的变量name的值Mozilla。我们可以看到displayName函数定义时是在makeFunc函数内部的,而最后执行时却是在window全局作用域中执行。并且成功输出了其所在的作用域中的name的值,这也就印证了《你不知道的javaScript》中对闭包的定义。
而以上代码起其实产生了两个闭包,其一是makeFunc和window之间形成的闭包,二便是displayName和makeFunc形成的闭包。

闭包的用法

看一个经典的栗子:

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

相信很多人都知道上述代码会输出10个11,这是因为for循环是在全局环境中执行的,而setTimeout的执行环境也是全局环境,其内部输出的变量i自然也就是全局的,当setTimeout执行的时候for循环早已结束了,所以输出了10次11 那么为了达到预期的输出1~10就可以用到我们上面所说的闭包了。

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

当然还可以使用let定义变量创建局部作用域从而解决这个问题

for (let i = 1; i <= 10; i++) {
	setTimeout(function () {
		console.log(i);
	}, 1000);
}
 

闭包的作用

  • 保护函数的私有变量不受外部的干扰。形成不销毁的栈内存。
  • 保存,把一些函数内的值保存下来。闭包可以实现方法和属性的私有化。

PS: 闭包虽然保存了内部变量,但是由于引用关系一直存在,所以容易造成内存泄漏。

回复

我来回复
  • 暂无回复内容