闭包的定义是能够访问自由变量的函数。
什么是自由变量呢?自由变量是在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。
由此,我们可以闭包有 函数 和函数能够访问的自由变量组成
例
var a=1;
function foo(){
console.log(a);
};
foo();
foo函数可以访问变量a,但是a既不是foo函数的局部变量,也是不是函数的参数,所以a就是自由变量。
那么,函数foo+函数访问的自由变量a不就是构成了一个闭包?
是的。
在《Javascript权威指南》中讲到,从技术的角度讲,所有的Javascript函数都是都是闭包。
网上闭包大多数是长这个样子
function f1(){
var n=999;
function f2(){
console.log(n);
}
}
f1();// 999
为什么跟我们平时看到的闭包不一样?
这是理论上的闭包,还有一个实践角度上的闭包,汤姆大叔翻译的闭包文章中的定义:
ECMAScript中,闭包指的是:
1.从理论角度讲,所有的函数,因为他们都在创建的时候就将上层上下文的数据保存起来了,哪怕是简单的全局变量也是如此,
因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域
2.从实践角度讲:一下函数才是闭包:
A:即使创建他的上下文已经销毁,他仍然存在(比如,内部函数从父函数中返回)
B:在代码中引用了自由变量
思考
让我们写个例子,例子来自《javaScript权威指南》,稍微有点改动:
var scope="global scope";
function checkscope(){
var scope="local scope";
function f(){
return scope;
}
return f;
}
var foo=checkscope();
foo();
我们先来分析一下这段代码中执行上细纹栈和执行上下文的变化情况
简要的执行过程:
1:进入全局代码,创建全局执行上下文,全局执行上下文压入执行上下文栈
2:全局执行上下文初始化
3:执行checkscope函数,创建checkscope函数执行上下文,checkscope执行上下文被压入执行上下文栈
4:checkscope执行上下文初始化初始化,创建变量对象,作用域链,this等
5:checkscope函数执行完毕,checkscope执行上下文从执行上下文栈中弹出
6:执行f函数,创建f函数执行上下文,f执行上下文被压入执行上下文栈
7:f函数执行上下文初始化,创建变量对象 作用域链 this等
8:f函数执行完毕,f函数上下文从执行上下文栈中弹出
这里有一个问题,
当f函数执行的时候。checkscope函数上下文已经被销毁了,怎么还会读取到checkscope作用域下的scope值呢
因为f执行上下文维护了一个作用域链:当f函数引用checkscope函数值的时候,即使checkscope被销毁了,但是
javascript依然会因为f函数作用域链找到他,因为活在内存中,因为javascript做到了这一点,从而实现了闭包这个概念
参考资源