有理解不对得地方请大佬及时指出!!!
想要理解闭包要先了解执行上下文的过程 引用另一篇文章的例子
1.执行过程
function foo(i) {
var a = 'hello';
var b = function privateB() {
};
function c() {
}
}
foo(22);
- 第1-9行 在全局上下文创建了一个foo的变量,并为其分配了一个函数变量, 2-8行描述了上述函数定义,存在了foo中如下
fooExecutionContext = {
// 创建作用域链(Scope Chain)
scopeChain: { ... },
// 创建变量,函数和参数。
variableObject: {
arguments: {
0: 22,
length: 1
},
i: 22,
c: pointer to function c()
a: undefined,
b: undefined
},
// ”this“的值。
this: { ... }
}
- 第1-9行 调用foo(22)时,在foo上下文中创建了a b并且赋与值,到c的时候发现已有就向下执行,到}得时候,函数执行上下文被销毁,从调用堆栈中删除,变量a、b和c()不再存在
fooExecutionContext = {
scopeChain: { ... },
variableObject: {
arguments: {
0: 22,
length: 1
},
i: 22,
c: pointer to function c()
a: 'hello',
b: pointer to function privateB()
},
this: { ... }
}
2.闭包
这很明显是一个闭包,我们分析一下上下文
let c = 4
function addX(x) {
return function(n) {
return n + x
}
}
const addThree = addX(3)
let d = addThree(c)
console.log('example partial application', d)
闭包的现象当一个函数被创建并传递或从另一个函数返回时,它会携带一个背包。背包中是函数声明时作用域内的所有变量
第1行 在全局上下文中创建了一个变量c赋值为4
第2-6行 全局上下文申明了一个变量addX并为其分配了一个函数定义,3-5行描述了函数定义
第7行
- 全局上下文中申明addThree变量后我们看到括号(), 需要执行或调用一个函数
- 查找全局上下叫addX的变量,找到后调用addX,调用addX函数创建一个新的addX上下文
- 创建x变量赋值为3
- 申明一个函数定义返回函数定义内容 删除addX上下文,返回函数定义赋值给了addThree 变量
这时我们可以看到addX被创建并返回了一个函数,背包里会携带变量x值为3
第8行
- 全局上下文中申明d变量后我们看到括号(), 需要执行或调用一个函数
- 查找全局上下文叫addThree 的变量,找到后调用addThree ,在全局上下文找到c变量传入,创建一个新的上下文
- 开始执行函数,创建n变量值为传入的c(4),寻找变量x,在查找本地或全局执行上下文之前,让我们检查一下闭包,发现闭包包含一个名为x的变量值为3,之后做加法运算返回一个值 赋值给d
最后 打印变量d
它是这样工作的,无论何时声明新函数并将其赋值给变量,都要存储函数定义和闭包。闭包包含在函数创建时作用域中的所有变量,它类似于背包。函数定义附带一个小背包,它的包中存储了函数定义创建时作用域中的所有变量。
执行上下文要点
- 函数定义可以存储在变量中,函数定义在程序调用之前是不可见的
- 每次调用函数时,都会(临时)创建一个本地执行上下文
- 函数在遇到return或右括号}时执行完成
- 当函数完成时,执行上下文将消失
总结
- 内部函数引用内部变量并被外部所引用称之为闭包
- 当一个函数被创建并传递或从另一个函数返回时,它会携带一个背包。背包中是函数声明时作用域内的所有变量
闭包的创建:编程语言设计者们为了解决Funarg问题而产生的一个副作用。Funarg的问题是早期使用动态作用域的编程语言如何解决外部变量在内存中存储的一个难点