闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
看下面这个代码的执行过程, 当我们调用 makeFunc1
的时候他里面会创建一个 名为 name
的变量, 当函数执行完毕的时候,函数内部的成员会被释放掉。如果这个函数里面又返回了一个函数,并且在返回的这个函数里又访问了外部函数的成员,其实这就是闭包。makeFunc2
其实就产生了闭包,当调用完 makeFunc2
的时候它会返回一个函数, myFunc
其实就引用了makeFunc2
中返回的函数,当外部对内部有引用的时候makeFunc2
内部的成员就不会被释放, myFunc
依然可以访问 makeFunc2
中名为 name
的变量
function makeFunc1() {
var name = "hellow closure";
}
makeFunc1()
function makeFunc2() {
var name = "hellow closure";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc2();
myFunc();
在做项目中可能会出现多次求2次方或者3次方或者n次方的情况,
Math.pow
可以求但是我们并不想重复的传入n次方的参数,所以我们把n次方函数抽离出来
Math.pow(4, 2)
Math.pow(5, 2)
function makePower(power) {
// 返回了一个函数
return function (number) {
// 访问了外部函数的成员 power
return Math.pow(number, power)
}
}
// 求平方
let power2 = makePower(2)
let power3 = makePower(3)
console.log(power2(2))
console.log(power3(2))
console.log(power2(4))
console.log(power3(4))
sources
下找到我们需要调试的文件,在第一次调用的地方打上断点,刷新一下浏览器call stack 函数调用栈
: 现在我们代码在script
标签里面,script
标签里面的代码都是在一个匿名函数中调用的scope 作用域
:全局作用域就是我们的window
对象call stack 函数调用栈
:我们继续看 call stack
这个位置, 此时栈顶是makePower
scope 作用域
:此时出现了一个local 也就是局部作用域,此时 makePower
的参数 power
的值是 2
makePower
已经执行完了,在看call stack
makePower
已经被移除了,我们开始说过函数执行完了会从执行栈上移除,同时作用域scope
也被移除,看不到了,此时多了一个Script
里面有一个power2
,这个power2
是我们用let
定义的 power2
变量。let
定义的会挂载到Script
上, 通过 var
定义的变量会在全局属性上Closure
,这个就是闭包相关的变量,里面有个power
他的值依然在内存中存在,通过控制台调试我们可以清楚地看到闭包发生的位置