(。・∀・)ノ゙嗨,我是你稳定更新、持续输出的勾勾。
作为一名前端搬砖人,提起闭包我就心梗。
我听得最多的一句话就是,“闭包,只可意会不可言传”。
伴随一周最开心的一刻(明天周末!),我们一起来谈谈这个十分抽象的话题。
简单来说,闭包就是指有权访问另一个函数作用域中的变量的函数。最常见的形态就是在一个函数的内部创建另一个函数。
结构
1) 外部函数的返回结果是一个函数,暂且称为内部函数。
2) 内部函数中使用了外部函数中的变量(成员)。
现象
1) 外部函数执行结束后,被内部函数使用的变量(成员)不会被销毁释放。
2) 生命周期:在整个代码执行结束时才销毁。
3) 作用域:只能在函数内部访问。
目的
1)每次去执行返回的内部函数,都可以使用该变量(成员)。
并且该变量(成员)的值可以变化,也就是说,该变量(成员)可以在函数多次执行过程中保存状态。
在其它一些语言中称为静态变量。
例:记录函数调用次数。
2)该变量可以被返回的内部函数访问。但是外部其它代码无法访问,防止意外修改,起到了保护作用。
Demo
例1:
// 闭包
function makeFn() {
let msg = '函数作为返回值'
return function() {
console.log(msg) // 内部函数访问外部函数的 msg
}
}
// 外部函数 makeFn 执行完, 应清理所有, 但其 msg 被 fn 使用, 所以 msg 不会销毁
const fn = makeFn()
fn() // 第一,msg 可以在 fn 中反复使用
console.log(msg) // 第二,msg 在外部这里是访问不到的,它被保护了起来
例2:
// 闭包
function once (fn) {
let done = false
return function () {
if (!done) { // 使用(引用)了外部函数的变量
done = true
fn.apply(this, arguments)
}
}
}
let pay = once(function (money) {
console.log(`支付: ${money} RMB`)
})
pay(5)
pay(5)
例3:
/*
求数字的平方
pow(5, 2)
pow(4, 2)
可以把 2 固定下来
*/
function makePower(power) {
return function (number) {
return Math.pow(number, power)
}
}
// 返回 求平方 的函数
let power2 = makePower(2)
console.log( power2(4) ) // 4的平方等于16
console.log( power2(5) ) // 5的平方等于25
// 返回 求立方 的函数
let power3 = makePower(3)
console.log(power3(4)) // 4的立方等于64
console.log(power3(5)) // 5的立方等于125
/*
我的理解:
power 作为参数,理解为外部函数的局部变量
内部函数中引用了它,内部函数被返回
所以,这是闭包的结构
函数参数的灵活性不同, 有的经常变, 有的偶尔变
可以把多参数的函数, 细粒度一些, 如上面代码
*/
/*
Call Stack 调用栈
Scope 作用域
Local 局部作用域
Global 全局作用域 通过var定义的变量会在全局
Script 通过let定义的变量可以在这个位置看到
Closure (makePower) 说明这个闭包引用了 makePower 外部函数中的变量(成员)
内部函数执行时, 才可以看到闭包相关内容, 即看到它所引用外部函数中的内容
*/
例4:
/*
不同级别员工的工资
生成计算工资的函数. 不同级别员工 基本工资不同
基本工资 base 12000, 15000
绩效工资 performance
*/
function makeSalary (base) {
return function (performance) {
return base + performance
}
}
// 基本工资为 12000 的 工资计算函数
let salaryLevel1 = makeSalary(12000)
// 基本工资为 15000 的 工资计算函数
let salaryLevel2 = makeSalary(15000)
console.log(salaryLevel1(2000)) // 总工资 14000
console.log(salaryLevel2(3000)) // 总工资 18000
不管你的理解如何,只要你能写出闭包的案例,你就已经一脚踏入了前端的世界。
周末快乐(●'◡'●)。
推荐阅读:
前端人因为 Vue3 的 Ref-sugar 提案打起来了!
点点“赞”和“在看”,保护头发,减少bug。