闭包:
函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包。
可以在另一个作用域(例子中的fn)中调用一个函数(例子中的makeFn)的内部函数(例子makeFn中的返回方法)并访问到该函数的作用域中的成员(makeFn中的msg成员)
闭包的核心作用就是把makeFn当中内部成员作用范围给延长了,正常执行下当makeFn被执行msg会被释放,但是如果makeFn中返回了一个成员,并且我们外部对这个成员有引用,那么makeFn中的成员在方法被执行完时,不会被释放,因为外部对内部有引用
//闭包
function makeFn(){
let msg='Hello zlw'
//可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员
return function(){
console.log(msg)
}
}
//调用完makeFn后会返回一个函数而这边的fn就引用了makeFn中返回的函数,即外部对内部内部有引用
//当外部对内部成员有引用makeFn内部成员(方法)不能被释放
const fn=makeFn()
fn()
//onece
function once(fn){
let done=false //虽然时局部变量但是是一个是否函数被执行的标记
return function(){
if (!done)
{
done=true
return fn.apply(this,arguments)
}
}
}
//当使用once,once先会创建一个局部变量done标记和返回一个函数
//通过pay这个变量来指向这个函数,也就是外部作用域对内部有引用,如果有引用
//once方法中的成员不会被释放掉
//当再次调用pay时,pay就是once中的匿名函数,并且可以获得外部的变量,延长了外部函数的变量的作用范围
let pay=once(function(money){
console.log(money+'RMB')
})
pay(5)
pay(5)
pay(5)
闭包的本质:
函数在执行的时候会放到一个执行栈上当函数执行完毕之后会从执行栈中移除(正常情况下once函数没有return一个函数,当函数在被执行时会被放到一个执行栈上,当函数执行完毕会在执行栈中移除,并且函数内部的变量也会移除,但是外部对这个函数有引用的话就不一样了,当once被执行完时,首先会在执行栈上移除,但是外部对这个函数内部成员有引用所以它内部的成员不会在内存中被移除)但是栈上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问到外部函数的成员
闭包的案例:
// 这边pow函数都是求得是二次方,用闭包得方法解决,要使用多次相同次方的函数闭包
// Math.pow(4,2)
// Math.pow(5,2)
function makePower(power){
return function(number){
return Math.pow(number,power)
}
}
let f2=makePower(2)
let f3=makePower(3)
console.log(f2(4))
console.log(f3(4))
//工资由基本工资和绩项工资组成,所以会出现基本工资的重复使用
// getSalary(12000,3000)
// getSalary(15000,5000)
// getSalary(16000,6000)
// getSalary(18000,3000)
// 使用闭包解决
function makeSalary(base){
return function(performance){
return base+performance
}
}
let makeSalary11=makeSalary(12000)
let makeSalary12=makeSalary(15000)
let makeSalary13=makeSalary(16000)
console.log(makeSalary11(3000))
console.log(makeSalary12(5000))
console.log(makeSalary13(6000))