你不知道的 JavaScript 系列之闭包

什么是闭包

闭包是可以读取其他函数内部变量的函数
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包

下面我们可以通过一段代码,清晰地展示了闭包:

function foo() {
	var a = 2;
	function bar() {
		console.log(a);
	}
	return bar;
}

var baz = foo();
baz(); // 2 这就是闭包的效果

函数 bar() 的词法作用域能够访问 foo() 的内部作用域,我们将 bar 所引用的函数对象本身当作返回值,在 foo() 执行后,将其返回值赋值给变量 baz 并调用 baz(),实际只是通过不同的标识符引用调用了内部的函数 bar()。此时,bar() 在自己定义的词法作用域以外的地方执行。

在 foo() 执行后,通常会期待 foo() 的整个内部作用域都被销毁,因为我们知道引擎有垃圾回收器用来释放不再使用的内存空间,由于看上去 foo() 的内容不会再被使用,所以很自然地会考虑对其进行回收。

而闭包的“神奇”之处正是可以阻止这种事情的发生。事实上内部作用域依然存在,因此没有被回收。

拜 bar() 所声明的位置所赐,它拥有涵盖 foo() 内部作用域的闭包,使得该作用域能够这一直存活,以供 bar() 在之后任何时间进行引用。

bar() 依然持有对该作用域的引用,而这个引用就叫做闭包
这个函数在定义时的词法作用域以外的地方被调用,闭包使得函数可以继续访问定义时的词法作用域。

无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包

function foo() {
	var a = 2;
	function baz() {
		console.log(a);
	}
	bar(baz);
}
function bar(fn) {
	fn(); // 闭包
}
foo();

是不是看着有点死板,但其实这就是我们常用的一种闭包形式

function wait(message) {
	setTimeout(function timer() {
		console.log(message);
	}, 1000)
}
wait('hello');

内置的工具函数 setTimeout 持有对一个参数的引用,这个参数也许叫做 fn 或者 func,或者其他类似的名字。引擎会调用这个函数,在例子中就是内部的 timer 函数,而词法作用域在这个过程中保持完整。这就是闭包。

本质上,无论何时何地,如果将函数当作第一级的值类型到处传递,你就会看到闭包在这些函数中的应用。在定时器、事件监听器、ajax请求或者任何其他的异步(或者同步)任务中,只要使用了回调函数,实际上就是在使用闭包

模块

还有其他的代码模式利用了闭包的强大威力,模块就是其中最强的一个。

function CoolModule() {
	var something = 'cool';
	var another = [1, 2, 3];
	function doSomething() {
		console.log(something);
	}
	function doAnother() {
		console.log(another.join());
	}
	return {
		doSomething: doSomething,
		doAnother: doAnother
	};
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1,2,3

模块模式需要具备的两个必要条件:

  • 必须有外部的封闭函数。该函数必须至少被调用一次;
  • 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。

最后

虽然闭包非常有用,但是不能过度使用。使用闭包时,所有的信息都会存储在内存中,直到 JavaScript 引擎确保这些信息不再使用或页面卸载时,才会清理这些信息。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值