闭包是JavaScript的一大谜团,关于这个问题有很多文章进行讲述,然而依然有相当数量的程序员对这个概念理解不透彻。闭包的官方定义为:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
一句话概括就是:闭包就是一个函数,捕获作用域内的外部绑定。这些绑定是为之后使用而被绑定,即使作用域已经销毁。
闭包只是JavaScript中最正常的现象,JavaScript中的闭包就像现实世界中的虫洞一样是一个充满神秘色彩的东西,实际上闭包只是一个巧妙的JS的语法事实做法,那就是在词法作用域的环境下写代码,而其中的函数也是值,可以随意传来传去 **当函数可以记住并且访问所在的词法作用域,即使函数实在当前词法作用域之外执行,这时就产生了闭包**
function a(){
console.log('我是外面的函数')
}
function b(){
a()
}
b() //调用b 可以访问a 打印出 我是外面的函数
但是想外面的调用里面的词法作用域就要想办法了 这个就是闭包的精髓所在和巧妙做法
function a(){
var z = 2;
function inside(){
console.log(z)
}
return inside
}
var outer = a()
outer();//2 ---这就是闭包 巧妙的将函数传了出来 让外部函数可以访问它本无法进入的作用域 这个外部函数就叫做闭包
以上outer()显然是可以被正常执行的,它在自己定义的词法作用域意外的地方执行。
下面再来一个例子 深刻理解闭包 之闭包英雄不问出处
var f
function foo(){
var a=2
function baz(){
console.log(a)
}
f = baz //将baz给全局f
}
function b() {
f() //这也是闭包 闭包英雄不问出处
}
foo();
b();//2
无论何种手段传递函数 事实上调用者都会对原始词法作用域的渗透和引用,无论在何处执行都会形成闭包。
很多程序员认为立即执行函数就是闭包 其实并不是
var a = 100
(function IIFE(){
console.log(a)
})()
以上代码并不是严格的闭包,代码中IIFE并不是在它本身的词法作用域以外执行的,它在定义时所在的作用域中执行,a是通过的普通词法作用域查找 而非闭包穿透引用的。以上都是闭包的小作用,闭包的大作用反复用在现在工程化的模块机制中,现代工程化模块机制大量运用闭包。
简单来说
闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的用途
闭包可以用在许多地方。它的最大用处有两个,
一个是前面提到的可以读取函数内部的变量
另一个就是让这些变量的值始终保持在内存中