蓝狮官网使用闭包实现点击按钮切换 toggle

前言
我以往在实现点击按钮切换dom元素样式的时候,蓝狮注册登陆使用的是在全局范围内定义一个flag变量,然后用true和false来对应不同的状态。

const btn = document.querySelector(‘#btn’); //获取按钮元素
let flag = false; //flag是全局变量

//事件监听绑定点击事件
btn.addEventListener(‘click’,function(){
if(flag){
//状态1
}else{
//状态2
}
flag = !flag; //切换状态(通过修改flag的值:true或false)
});

//…如果代码量很多的话,我们可能在其他地方不小心使用着同样叫做flag的变量

flag = doSomethingToFlag(); //其他代码可能对flag的值进行了(意料之外的)修改
这个flag变量其实本意上只是用在按钮的点击事件上,但是flag位于全局范围内,其他代码都可以对flag的值进行修改,从而可能导致意料之外的情况发生。因此,使用全局变量表示不同状态是不可取的做法。

最近在学习闭包的概念,尝试着使用闭包实现点击按钮切换不同状态。

分析
使用闭包我们可以把表示状态的flag变成私有变量。

const btn = document.querySelector(‘#btn’); //获取按钮元素

function click(){
let flag = true; //这里的flag不再是全局变量

function closure(){
    if(flag){
        console.log('on');  //这里表示状态1
    }else{
        console.log('off'); //这里表示状态2
    }
    flag = !flag;   //切换状态
}
return closure;

}

btn.addEventListener(‘click’,click()); //绑定点击事件

console.log(flag); //报错:flag is not defined
我们在click()函数内部定义了closure()函数,当closure()函数被返回并在其他地方被使用后,它仍然引用着flag,这就导致了click()函数被销毁,但是flag不会被销毁,也就是形成了闭包。

这里稍微对代码做一些改进,使其复用性更高,也就是封装toggle()函数:

//toggle()函数接收一个按钮和两个函数:on()和off();
//其中on()表示第1种状态要执行的内容,off()表示第2种状态要执行的内容
function toggle(btn, on, off) {
//使用闭包
function click() {
let flag = true;

    function closure() {
        if (flag) {
            on();//这里执行状态1要执行的内容
        } else {
            off();//这里执行状态2要执行的内容
        }
        flag = !flag;
    }

    return closure;
}

//为按钮绑定点击事件
btn.addEventListener('click', click());

}
将功能封装好后,就可以很方便的将toggle事件绑定到按钮上:

const btn = document.querySelectorAll(‘.btn’); //获取若干个按钮

for (let i = 0; i < btn.length; i++) {//使用for循环为这些按钮都绑定toggle事件
//toggle函数的三个参数分别是:按钮DOM元素、状态1要执行的内容、蓝狮官网状态2要执行的内容
toggle(btn[i],
function on() {
//doSomething:这里填入状态1要执行的代码
},
function off() {
//doSomething:这里填入状态2要执行的代码
});
}
经过测试可以发现,各个按钮对应的flag是独立的,互不干扰的。这是因为:

每一次绑定点击事件时,toggle()函数内部的click()函数占有一定内存空间,而函数调用后,内存被回收,flag由于闭包的特性被保留下来;

又因为每次调用click()函数开辟的是不同的内存空间,因此内部对应的flag也是不同的,故每一个按钮都能和一个flag一一对应,不会互相干扰。

0 Comments
Leave a Reply