什么是闭包(closure):
当你声明一个局部变量时,这个局部变量有作用域,通常局部变量值只存在于你定义的Block or Function中:
function() { var a = 1; console.log(a); // works } console.log(a); // fails
如果你想要尝试访问一个局部变量,大多数的语言都会在当前作用域去找,然后去找上一层的作用域,最后找到根作用域(root scope)
var a = 1; function() { console.log(a); // works } console.log(a); // works
当一个Block or Function工作完后,我们就不需要它的局部变量了,所以我们就把它丢出内存了
这是我们普遍希望这样做的
闭包就是永久存在的局部变量
举个例子吧:
outer = function() { var a = 1; var inner = function() { console.log(a); } return inner; // this returns a function } var fnc = outer(); // execute outer to get inner fnc();
这里我定义了一个函数内的函数。内部函数可以访问所有外部函数的局部变量,包括a
。该变量a
在内部函数的范围内。
通常,当一个函数退出时,它的所有局部变量都会被消灭。但是,如果我们返回内部函数并将其分配给一个变量fnc
,以便它在outer
退出后保持不变,那么在inner
定义范围内的所有变量也会保留。该变量a
已被关闭 - 它在闭包内。
请注意,该变量a
是完全私有的fnc
。这是一种使用JavaScript等函数式编程语言创建私有变量的方法。
正如您可能会猜到的那样,当我使用fnc()
它会打印出a
“1”的值。
在没有闭包的语言中,a
当函数outer
退出时,变量将被垃圾收集并抛弃。调用fnc会引发错误,因为a
不再存在。
在JavaScript中,变量a
持续存在,因为变量作用域是在函数首次声明时创建的,只要函数继续存在,该变量就一直存在。
a
属于作用域outer
。作用域inner
有一个指向范围的父指针outer
。fnc
是一个指向的变量inner
。a
只要fnc
持续存在,就会持续存在。a
在闭包之内。
这里我定义了一个函数内的函数。内部函数可以访问所有外部函数的局部变量,包括a
。该变量a
在内部函数的范围内。
通常,当一个函数退出时,它的所有局部变量都会被吹走。但是,如果我们返回内部函数并将其分配给一个变量fnc
,以便它在outer
退出后保持不变,那么在inner
定义范围内的所有变量也会保留。该变量a
已被关闭 - 它在闭包内。
所以闭包总结为:
如果在一个内部函数里,对外部作用域(但不是在全局作用域的变量)进行引用,那么内部函数就会被认为是闭包。