通过一个简单的计数器案例理解JS中闭包概念
首先我们来看一个基于传统JS实现的定时器案例:
let second = 0
function counter(){
second +=1
return second
}
const recordSecond=setInterval(() => {
if(second === 10){
clearInterval(recordSecond)
console.log('计时结束')
return
}
console.log(`${counter()}秒`)
}, 1000);
在这个案例中,我们定义了一个counter函数进行计数,接着定义一个recordSecond定时器,每隔1s执行一次counter函数执行计数操作,当计数到10的时候,清除计数器。
这段代码很好理解,唯一需要注意的是,这里counter函数的执行是在console.log里面执行的,这个操作比较独特,在开发工作中可以借鉴。
接下来,我们看一下使用闭包实现的计数器:
function counter(){
let second = 0
function doCounter(){
if(second === 10 ){
clearInterval(recordSecond)
console.log('记录时间结束')
return
}
second +=1
console.log(`${second}秒`)
}
return doCounter
}
const doCounterFn=counter()
const recordSecond = setInterval(() => {
doCounterFn()
}, 1000);
在这个案例中,我们定义了一个counter函数,在counter函数里面又定义了一个子函数doCounter,在doCounter中我们引用了外层函数的变量second,并在每次执行的时候将second变量+1。
这里内部的doCounter函数和外部的counter函数就形成了一个闭包,拥有只有自己作用域里面才能使用的second变量。
接下来,我们吧counter函数赋值给doCounterFn,我们看这段代码:
const doCounterFn=counter()
这段代码是什么意思呢?意思就是:执行counter函数,并将返回值赋值给doCounterFn,我们需要明确这一点:doCounterFn接受的是counter 返回的 doCounter子函数,doCounter子函数又拥有自己的作用域(即与counter构成的闭包)。
在接下来的代码中,我们通过定义定时器,执行doCounterFn函数,也就是执行了一个拥有自己独特作用域的doCounter函数,doCounter函数拿到外部的second变量,并对其执行+1操作,然后在下次执行的时候,doCounter拿到的变量是执行+1操作后的second变量,这看起来就像函数能够记住曾经使用过的变量。