讲一讲闭包

闭包的定义

MDN 对闭包的定义为:闭包就是那些能够访问自由变量的函数。

什么是自由变量呢?

自由变量是指在函数中使用,但既不是函数参数也不是函数局部变量的变量。

由此可见闭包包含两部分:函数+函数能够访问的自由变量,从技术的角度讲,所有的JavaScript函数都是闭包

javascript 复制代码
var a = 1;

function foo() {
    console.log(a);
}

foo();

但这只是理论上的闭包,还有实践角度上的闭包:

ECMAScript中,闭包指的是:

  1. 从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域;
  2. 从实践角度:以下函数才算是闭包:
    1. 即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回);
    2. 在代码中引用了自由变量;

这就涉及到两个知识点:执行上下文和变量对象

对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

举一个简单的例子:

javascript 复制代码
var scope = "global scope"
function checkscope(){
	var scope = "local scope"
	function f(){
		console.log(scope)
	}
	return f
}
checkscope()()

执行过程:

  1. 创建全局执行上下文,全局执行上下文压入执行上下文栈,全局执行上下文初始化,初始化的同时,checkscope 函数被创建,保存作用域链到函数的内部属性\[scope];
javascript 复制代码
ECStack = [
	globalContext
]
globalContext = {
	VO: [global],
	Scope: [globalContext.VO],
	this: globalContext.VO
}
checkscopeContext: {
	scope: [globalContext.VO]
}
  1. 执行checkscope函数,创建checkscope 执行上下文,被压入执行上下文栈;
  2. checkscope函数执行上下文初始化,创建变量对象、作用域链、this等,同时 f 函数被创建,保存作用域链到 f 函数的内部属性\[scope];
javascript 复制代码
ECStack = [
	checkscopeContext,
	globalContext
]
checkscopeContext: {
	AO: {
		arguments: {
			length: 0
		},
		scope: undefined,
		f: reference to function f(){}
	},
	Scope: [AO, globalContext.VO],
	this: undefined
}
  1. checkscope函数执行完毕,从执行上下文栈弹出;
javascript 复制代码
ECStack = [
	globalContext
]
  1. 执行 f 函数,创建 f 执行上下文,被压入执行上下文栈;
javascript 复制代码
ECStack = [
	fContext,
	globalContext
]
fContext = {
	AO: {
		arguments: {
			length: 0
		},
	},
	Scope: [AO, checkscopeContext.AO, globalContext.VO],
	this: undefined
}
  1. f 函数执行完毕,从执行上下文栈弹出;
  2. 全局执行上下文从执行上下文栈弹出。

f 函数在执行的时候, f 执行上下文维护了一个作用域链,

javascript 复制代码
fContext = {
    Scope: [AO, checkscopeContext.AO, globalContext.VO],
}

因为这个作用域链,f 函数依然可以读取到 checkscopeContext.AO 的值,说明当 f 函数引用了 checkscopeContext.AO 中的值的时候,即使 checkscopeContext 被销毁了,但是 JavaScript 依然会让 checkscopeContext.AO 活在内存中,f 函数依然可以通过 f 函数的作用域链找到它,正是因为 JavaScript 做到了这一点,从而实现了闭包这个概念。

写一个简单的闭包

javascript 复制代码
var arr = []
for(var i = 0; i < 3; i++){
	arr[i] = function(i){
		return function(){
			console.log(i)
		}
	}(i)
}
arr[0]()
arr[1]()
arr[2]()
相关推荐
AI人工智能+电脑小能手2 分钟前
【大白话说Java面试题 第151题】【06_Spring篇】第11题:说一下 Spring Bean 的生命周期?
java·开发语言·后端·spring·面试
丨我是张先生丨5 分钟前
日语单词 Web Page
前端·css·css3
广州浮点FLOATLIC15 分钟前
Creo 许可证利用率怎么优化:制造企业该先看共享规则,还是先看模块占用结构
java·开发语言
wuyk55524 分钟前
21. 嵌入式面试避坑指南:sizeof 是关键字,不是函数!
c语言·开发语言·stm32·单片机·嵌入式硬件
2601_9624408426 分钟前
计算机毕业设计之jsp教室管理系统
java·开发语言·笔记·分布式·算法·课程设计·推荐算法
禅思院2 小时前
AI对话前端从入门到崩溃:一个长对话引发的五层优化战争【引子】
前端·面试·架构
TrisighT2 小时前
Electron 鸿蒙 PC 上点外链唤醒应用,我试了 6 种写法只有 1 种能跑
前端·electron·harmonyos
2501_930707782 小时前
如何将HTML文件转换为纯文本(详细步骤指南)
前端·html
天才熊猫君3 小时前
配置与数据分离:一种可视化搭建的属性编辑方案
前端·javascript
林希_Rachel_傻希希3 小时前
web性能之相关路径——AI总结
前端·javascript·面试