【重识前端】闭包与模块

本文探讨了JavaScript中的闭包和模块,从定义到实践应用,包括常见的闭包场景、闭包与循环的关系,以及从上古时代到现代的模块系统,如AMD、CMD和ES Module的区别。通过实例解析了闭包的工作原理和模块的演变过程,帮助读者深入理解这两个关键概念。
摘要由CSDN通过智能技术生成

最近在写【重拾前端】系列,下面有几个快速通道,大家自取

【重识前端】原型/原型链和继承

【重识前端】闭包与模块

【重识前端】全面攻破this

【重识前端】一次搞定JavaScript的执行机制

【重识前端】什么是BFC、IFC、GFC 和 FFC

【重识前端】深入内存世界

前言

回忆我前几年的时光,大量使用 JavaScript 但却完全不理解闭包是什么。总是感觉这门语 言有其隐蔽的一面,如果能够掌握将会功力大涨,但讽刺的是我始终无法掌握其中的门 道。

JavaScript中闭包无处不在,你只需要能够识别并拥抱它。

最后你恍然大悟:原来在我的代码中已经到处都是闭包了,现在我终于能理解它们了。理 解闭包就好像 Neo3 第一次见到矩阵 4 一样。

定义

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用 域之外执行。

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

这样可能还不够直观,我们再修改一下。

function foo() {
    
  var a = 2;
	function bar() {
    
    console.log( a ); // 2
	}
	return bar; 
}
var baz = foo();
baz(); // 2 —— 朋友,这就是闭包的效果。

其实,在正常情况下,我们调用完foo之后,JavaScript检测到后续不会再用到他了, 所以他的内部作用域就会被回收♻️。(涉及到垃圾回收机制,后续的文章我们会说到。)

闭包的神奇之处就在于他可以阻止♻️的发生。因为事实上内部作用域已然存在,那么又有谁在使用呢?哦~是我们的bar在使用。

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

bar() 依然持有对该作用域的引用,而这个引用就叫作闭包。

所以我说说我自己的理解:

闭包是一个运行时的概念,如果只是声明或者定义。即使他符合闭包的要求那他也不能成为一个真正的闭包。为什么?因为内存地址并没有开始分配,闭包只是分配之后那一块地址没有被回收而已。

再回到我们最开始的函数:

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

一个函数foo内有一个函数bar。并且函数bar用到了函数foo的变量。那么我们就可以称这个引用过程为“闭包”。但是我们这个函数foo必须被调用,所以我们的例子地下调用了一下函数foo。

再回到我们那个较为清晰的例子

function foo() {
    
  var a = 2;
	function bar() {
    
    console.log( a ); // 2
	}
	return bar; 
}
var baz = foo();
baz(); // 2 —— 朋友,这就是闭包的效果。

这个应该是大众认知上非常经典的一个闭包了吧?但是假如说这个foo函数没有被调用,那么我认为他就不是一个闭包。

实践

常见的闭包

前面的代码片段有点死板,并且为了解释如何使用闭包而人为地在结构上进行了修饰。你已经写过的代码中一定到处都是闭包的身影。 现在让我们来搞懂这个事实。

function wait(message) {
   
	setTimeout( 
		function timer() {
    
			console.log( message );
	}, 1000 ); 
}
wait( "Hello, closure!" );

这个例子非常常见,代码很简单,就是1秒钟之后输出我们传入的参数。

但是我们仔细看就能看见闭包的影子,一秒钟之后,message还是可以被timer访问到。并没有被回收♻️掉。

这就是闭包

本质上无论何时何地,如果将函数(访问它们各自的词法作用域)当作第一 级的值类型并到处传递,你就会看到闭包在这些函数中的应用。在定时器、事件监听器、 Ajax 请求、跨窗口通信、Web Workers 或者任何其他的异步(或者同步)任务中,只要使 用了回调函数,实际上就是在使用闭包!

闭包与循环

说到这里肯定有人马上就想到了最经典的面试题:请写出以下的输出内容

for (var i=1; i<=5; i++
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值