闭包的使用一些总结

我们看一下官方对于闭包的解释,走起

	闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
	自己的工作角度理解:闭包是一个函数,另外就是他是函数内的函数,他有需求,想要访问外部的作用域,那到底工作中怎么用呢?我用几个小例子给大家模拟一下

第一个小例子 我们想要打印一下一个变量调用值–情况

var a = 10;
        function fn(){
            a--;
            console.log(a)
        }

在这里插入图片描述
注释:有没有发现我在图片中打岔的地方,跟大家说一下原因,因为我声明的是全局变量,所以造成了在浏览器控制台任何人都可以控制我的变量,这个是老板不喜欢的,所以你懂得!!!

那么我们把全局变量放在函数中中不?

function fn(){
            var a = 10;
            a--;
            console.log(a)
        }

在这里插入图片描述
解释:这时候我们发现控制台不能被控制我的a变量,但是我们发现业务逻辑没有了,没有实现–情况,大家想一想,你的函数是不是一直都是调用的a=9,有人会说那不应该一直是8吗,因为流程是自上往下的,所以一直都是9,是一个自上往下的过程,大家要记清楚。

那我们再试试下边的情况

function fn(){
            var a = 10;
            return function fn1(){
                a--;
                console.log(a)
            }
        }
        var niu = fn()

在这里插入图片描述
解释:我们会发现 业务需求达到了,老板的目的也达到了,在工作中我们经常用闭包。

总结 闭包要素有哪些???

1.是一个嵌套函数;
2.嵌套函数中内部函数要访问外部函数的变量;
3.内部函数作为一个返回值供使用
4.创建一个变量函数去接着这个闭包,让其使用

这时候我们明白闭包可以防止全局变量环境污染,但是单独的局部变量不能长期驻足,所以我们发现第二种情况函数用完销毁,重新用重新赋值,那么我们闭包这种机制就完美解决这个问题,让我们长期保留(不会在调用结束后,被垃圾回收机制回收)也能够不造成全局变量的环境污染。

世界上没有完美的事情,因为闭包会占更多的内存,因为她属于Function,会消耗更多的内存空间。

下边我再说一下工作中我们在哪些常见的场景使用闭包?

第一个 setTimeout()
function func(param){
        return function(){
            alert(param)
        }
        }
        let fn = func('1');
        setTimeout(fn,1000)
第二个 回调
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <link rel="stylesheet" href="">
</head>
<style>
    body{
        font-size: 12px;
    }
    h1{
        font-size: 1.5rem;
    }
    h2{
        font-size: 1.2rem;
    }
</style>
<body>

    <p>哈哈哈哈哈哈</p>
    <h1>hhhhhhhhh</h1>
    <h2>qqqqqqqqq</h2>

    <a href="#" id="red">red</a>
    <a href="#" id="blue">blue</a>
    <a href="#" id="yellow">yellow</a>

<script>
    function changeSize(color){
        return function(){
            document.body.style.color = color;
        };
    }

    var red = changeSize('red');
    var blue = changeSize('blue');
    var yellow = changeSize('yellow');

    document.getElementById('red').onclick = red;
    document.getElementById('blue').onclick = blue;
    document.getElementById('yellow').onclick = yellow;
    //我们定义行为,然后把它关联到某个用户事件上(点击或者按键)。我们的代码通常会作为一个回调(事件触发时调用的函数)绑定到事件上
</script>
</body>
</html>
第三个封装一个私有变量
//共享的环境创建在一个匿名函数体内,立即执行。
    //环境中有一个局部变量一个局部函数,通过匿名函数返回的对象的三个公共函数访问。
    var a = (function(){
        let b = 0;
        function niu(val){
            b += val;
        };
        return {
            jiaYi:function(){
                niu(1)
            },
            jianYi:function(){
                niu(-1)
            },
            value:function(){
                return b
            }
        }
    })()
    a.value();//0
    a.jiaYi();
    console.log(a.value())//1
    a.jianYi();
    console.log(a.value())//0
为节点遍历给事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<link rel="stylesheet" href="">
</head>
<body>

<p id="info">123</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>

<script>
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        var item = infoArr[i];
        document.getElementById(item.id).onfocus = function(){
            showContent(item.content)
        }
    }
}
setContent()

</script>
</body>
</html>


上述代码原本想实现,点击不同的框显示不同的信息,结果现在都只会显示最后一项“your age”

分析:

循环中创建了三个闭包,他们使用了相同的词法环境item,item.content是变化的变量
当onfocus执行时,item.content才确定,此时循环已经结束,三个闭包共享的item已经指向数组最后一项。
解决:

/**
 * 解决方法1     通过函数工厂,则函数为每一个回调都创建一个新的词法环境
 */
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function callBack(content){
    return function(){
        showContent(content)
    }
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        var item = infoArr[i];
        document.getElementById(item.id).onfocus = callBack(item.content)
    }
}
setContent()

/**
 * 解决方法2        绑定事件放在立即执行函数中
 */
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        (function(){
            var item = infoArr[i];
            document.getElementById(item.id).onfocus = function(){
                showContent(item.content)
            }
        })()//放立即执行函数,立即绑定,用每次的值绑定到事件上,而不是循环结束的值
    }
}
setContent()

/**
 * 解决方案3        用ES6声明,避免声明提前,作用域只在当前块内
 */
function showContent(content){
    document.getElementById('info').innerHTML = content;
};

function setContent(){
    var infoArr = [
        {'id':'email','content':'your email address'},
        {'id':'name','content':'your name'},
        {'id':'age','content':'your age'}
    ];
    for (var i = 0; i < infoArr.length; i++) {
        let item = infoArr[i];      //限制作用域只在当前块内
        document.getElementById(item.id).onfocus = function(){
            showContent(item.content)
        }
    }
}
setContent()

喜欢的老铁们,点个赞吧!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值