MDN官方定义
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
可能由于是翻译问题,这段定义读的实在绕,不懂可接着看下面。
闭包最简代码
先来看一段闭包的最简代码
let codeHua=22222;
function closure() {
let codeHua = 1; // codeHua是父函数closure 创建的局部变量
function displaycodeHua() { // displaycodeHua() 是子函数,一个闭包
console.log(codeHua); // 使用了父函数中声明的变量
}
displaycodeHua();//1
}
closure();
初步理解
闭包是函数里面套函数,然后子函数能拿到父函数的变量。
闭包代码升级
接下来我们对代码进行一个升级,父函数中不执行子函数,而是返回子函数,并在每次log后++
let codeHua=22222;
function closure() {
let codeHua = 1; // codeHua是父函数closure 创建的局部变量
function displaycodeHua() { // displaycodeHua() 是子函数,一个闭包
console.log(codeHua); // 使用了父函数中声明的变量
codeHua++;//增加1
}
return displaycodeHua;//返回子函数
}
console.log(closure());// function displaycodeHua() {console.log(codeHua);}
let myclosure=closure();
let anothermyclosure=closure();
myclosure();//1
myclosure();//2
myclosure();//3
anothermyclosure();//1
在一些编程语言中,一个函数中的局部变量仅存在于此函数的执行期间。一旦closure() 执行完毕,name变量将不能再被访问,程序无法运行。
然而在JavaScript却可以正常运行,正是因为形成了闭包。
定义理解
我们回到广官方定义的一段话:
闭包是由函数以及声明该函数的词法环境组合而成的,而该环境包含了这个闭包创建时作用域内的任何局部变量。
在上述代码中,myclosure是执行closure时创建的displaycodeHua函数的引用,displaycodeHua函数维持了一个对它的词法环境(变量codeHua在于其中)的引用。因此,当myclosure被调用时,变量codeHua仍然可用,其值就被传递。
myclosure与anothermyclosure都是闭包,但是保存了不同的词法环境。
通俗点说就是闭包可以保留变量的值,不造成变量污染。
闭包的缺点
处理速度慢,内存消耗大,非特定任务不推荐使用。