JS系列第五弹:JS基础之闭包

零、导论

一,表象

1- 函数里面返回一个函数
2- 把局部变量交给全局使用
3- 把内函数作为参数传递给外函数,外函数返回内函数的调用

二,解析

闭包在很多语言中都有其概念,当我们接触到闭包这个概念时,没有例举案例,所以为了让我们尽早的知道什么是闭包,我们按照经验总结了其表现特征,如上述1,2,3点所说。
而闭包正解应该由MDN对闭包的官方解释来解读:
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

三,总结

1- 闭包是一个函数和作用域的总和。我们把它看做一个背包
2- js中,我们创建一个函数时,就会产生一个闭包。该闭包中包含了函数的作用域。
3- 闭包的出现让内部函数可以反问外部函数的作用域

除去以上三点。其他任何关于闭包的解释都是非官方的。

如果我们想了解闭包。就需要先了解两个概念:函数&作用域。
而如果是在js中,除了作用域之外,我们还需了解一个东西叫做上下文。作用域在上节中已经解释过了,这节我们直接从上下文入手。

一、上下文

1- JS代码在执行前,JS引擎总要做一番准备工作,这份工作其实就是创建对应的执行上下文;
2- 执行上下文有且只有三类,全局执行上下文,函数上下文,与eval上下文

1- 全局执行上下文
全局执行上下文只有一个,在客户端中一般由浏览器创建,也就是我们熟知的window对象,我们能通过this直接访问到它。
全局对象window上预定义了大量的方法和属性,我们在全局环境的任意处都能直接访问这些属性方法,同时window对象还是var声明的全局变量的载体。我们通过var创建的全局对象,都可以通过window直接访问。
2- 函数执行上下文
1- 函数执行上下文可存在无数个,每当一个函数被调用时都会创建一个函数上下文;
2- 需要注意的是,同一个函数被多次调用,都会创建一个新的上下文。
3- eval函数执行上下文:执行在eval函数内部的函数也有自己的函数上下文

4- 执行上下文栈也叫调用栈,当js解释器运行的时候,执行栈就会用于存储代码执行期间创建的所有上下文,具有LIFO(Last In First Out后进先出,也就是先进后出)的特性。U型
5- JS代码首次运行,都会先创建一个全局执行上下文并压入到执行栈中,之后每当有函数被调用,都会创建一个新的函数执行上下文并压入栈内;由于执行栈LIFO的特性,所以可以理解为,JS代码执行完毕前在执行栈底部永远有个全局执行上下文。

如下代码的执行逻辑应该是:
1- 函数f1, f2, f3被定义, 调用f1函数, 进入f1函数的执行上下文, 先调用f2函数,进入f2中的执行上下文,然后打印1
2- f2中的执行上下文中, 调用f3函数, 进入f3函数的执行上下文, 然后再打印2
3- f3中的执行上下文, 打印3
所以结果应该是3, 2, 1依次被打印
按顺序写应该是, 调用f1 => 进入f1执行上下文 => 调用f2 => 进入f2执行上下文 => 调用f3 => 进入f3执行上下文 => 打印3 => 返回f2的执行上下文 => 打印2 => 返回f1的执行上下文 => 打印1
在这里插入图片描述

上下文执行逻辑如下: 
1. JavaScript创建一个新的函数执行上下文
2. 这个执行上下文将有它自己的一组变量,这些变量将是这个执行上下文的本地变量。
3. 新的执行上下文被推到到执行堆栈中
4. 直到遇到return语句或一个结束括号},函数执行结束
当函数结束时:
1. 弹出执行栈
2.函数将返回值返回调用上下文
3.这个本地函数执行上下文被销毁

二、闭包

真正的闭包

1- 无论何时声明新函数并将其赋值给变量,都要存储函数定义和闭包。闭包包含在函数创建时作用域中的所有变量,它类似于背包。函数定义附带一个小背包,它的包中存储了函数定义创建时作用域中的所有变量。

2- 在全局作用域中创建的函数创建闭包,但是由于这些函数是在全局作用域中创建的,所以它们可以访问全局作用域中的所有变量,闭包的概念并不重要。

3- 当函数返回函数时,闭包的概念就变得更加重要了。返回的函数可以访问不属于全局作用域的变量,但它们仅存在于其闭包中。

4- 闭包的方法是通过背包的类比。当一个函数被创建并传递或从另一个函数返回时,它会携带一个背包。背包中是函数声明时作用域内的所有变量。

5- 注意事项:容易导致内存泄漏。闭包会携带包含其它的函数作用域,因此会比其他函数占用更多的内存。过度使用闭包会导致内存占用过多,所以要谨慎使用闭包。

6- MDN对闭包的官方解释:
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
闭包是绑定在一起(封闭)的函数及其周围状态(词汇环境)的引用的组合。换句话说,闭包允许您从内部函数访问外部函数的scope。在JavaScript中,每次创建函数时,都会在函数创建时创建闭包。

如有问题,可以针对以下代码进行跟栈看看作用域

function createCounter() {
	let counter = 0
	const myFunction = function() {
		counter = counter + 1
		return counter
	}
	return myFunction
}
const increment = createCounter()
const c1 = increment();const c2 = increment();const c3 = increment();
console.log('result', c1, c2, c3)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值