作为原生JS程序猿,闭包函数可能是经常被提及的一个知识,然而问道闭包函数是什么的时候,大家可能会用一句话概括。闭包就是在一个函数内,返回另外一个函数。这感觉像是一个回答,然而又暴露出更多的问题。为什么要用返回的函数而不是直接调用这个函数?闭包函数有哪些优点?闭包函数又有哪些缺点?很显然,简单的概括为在一个函数内返回另外一个函数并不能把闭包的精髓展现出来。接下来让我们一起来探究一下闭包的那些事。
前言:在将闭包函数前,首先了解一下js中变量作用域。
function father () {
let f1 = '这是父级作用域变量'
son()
console.log('父级调用:'+f1)
console.log('父级调用:'+s1)
function son () {
let s1 = '这是子级作用域变量'
console.log('子级调用:'+f1)
console.log('子级调用:'+s1)
}
}
father ()
// 子级调用:这是父级作用域变量
// 子级调用:这是子级作用域变量
// 父级调用:这是父级作用域变量
// Uncaught ReferenceError: s1 is not defined
// at father (<anonymous>:5:25)
// at <anonymous>:1:1
运行以上代码,会发现,子级可以使用父级作用域的变量,而父级不能使用子级作用域的变量。这也好理解,儿子拿父母的东西,顺理成章。父母向子女索取就有一定难度了(在此希望大家都能羔羊跪乳,乌雀反哺。能孝敬父母)。以上大概就是作用域的概念,简单来说就是当前的变量只能在当前作用域内使用。
为什么要用闭包?
在上面讲作用域的时候提到子级作用域可以获取到父级作用域,而父级作用域拿不到子级作用域。那么问题来了,如果父级作用域非得取子级作用域的变量怎么办呢?(父母年老时,向子女索要赡养费,子女拒不赡养父母,该怎么办呢?很简单,指定一个规则,让子女必须给父母一定的赡养费)
// 支付赡养费方法
function getMoney() {
let money = 500
return money
}
let fatherMoney = getMoney()
let fatherMoney2 = getMoney()
let fatherMoney3 = getMoney()
fatherMoney // 500
fatherMoney2 // 500
fatherMoney3 // 500
运行以上代码会发现一个bug,就是每次调用getMoney方法都会返回500,这与我们的初心相悖。我们希望的是每月只能获取一次500,也就是money不是每次运行都进行初始化。接下来就要用闭包的思路了。
// 定义获取赡养费函数
function getMoney() {
let money = 500 // 初始化赡养费金额
return function () {
let m = money >0 ? money : 0 // 如果赡养费存在则返回,否则返回0
money = money - m
return m
}
}
let fatherGetMoney = getMoney() // 返回一个函数
fatherGetMoney() // 返回500
fatherGetMoney() // 返回0
fatherGetMoney() // 返回0
运行以上代码,money只有在调用getMoney时初始化一次,符合我们需求。接下来有另一个疑问,此时father调用了获取赡养费的方法,mother还没有得到赡养费怎么办?
let motherGetMoney = getMoney()
motherGetMoney() // 返回500
motherGetMoney() // 返回0
motherGetMoney() // 返回0
此时我们发现mother只需要重新调用getMoney函数,即可重新初始化money。这时候我们会发现let fatherGetMoney = getMoney()和let motherGetMoney = getMoney()是两个独立的,互相不干扰的。
总结:
使用闭包函数,在闭包函数中的属性会一直占用内存,不会被回收。
闭包函数相对独立,不会互相干扰。
闭包函数使用私有变量,避免全局变量污染。
缺点:闭包函数会常驻内存,使用不当容易造成内存溢出,同时会影响性能。
写在最后:本文通过案例分析,了解闭包的原理,其中一些案例可能不太严谨,期待大家的指正。希望能通过本文,让大家更好的理解闭包,感谢大家的,共同进步