嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2016-07-26 1145 次浏览 标签 : javascript闭包

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

需求

要分周期显示三个红包。我通过在服务段输出每个红包离开始还有多少秒,离结束还有多少秒,然后在 js 里循环控制各个红包做倒计时,统计。

var hongbaoList = [
    {id: 1, startTs: -10, endTs: 9, url: "1.jpg"},
    {id: 2, startTs: 10, endTs: 29, url: "2.jpg"},
    {id: 3, startTs: 30, endTs: 59, url: "3.jpg"},
];

错误

for (var i in hongbaoList) {

    hongbao = hongbaoList[i];

    if (hongbao.startTs <= 0 && hongbao.endTs >= 0) {
        // 显示该红包
        console.log("现在显示的红包:" + hongbao.id);
    }

    // 未开始
    if (hongbao.startTs > 0 && hongbao.startTs < 3600 * 24) {
        setTimeout(function () {
            // 显示该红包
            console.log("显示红包:" + hongbao.id);
        }, (hongbao.startTs * 1000));
    }

    // 未结束
    if (hongbao.endTs > 0 && hongbao.endTs < 3600 * 24) {
        setTimeout(function () {
            // 隐藏该红包
            console.log("隐藏红包:" + hongbao.id);
        }, (hongbao.endTs * 1000));
    }
}

输出结果

现在显示的红包:1
隐藏红包:3
显示红包:3
隐藏红包:3
显示红包:3
隐藏红包:3

为什么会出现这样的情况,一直显示第三个红包呢?

因为在 for 循环完最后一次的时候

hongbao = hongbaoList[2]

这样会把之前的临时变量覆盖,那么定时器里面的变量根据 js 的变量作用域的范围,导致 setTimeout 回调函数里面的变量都被最后一次循环覆盖了。

下面改写为闭包的方式,那么就不会出现变量污染了。

正确

for (var i in hongbaoList) {

    hongbao = hongbaoList[i];

    if (hongbao.startTs <= 0 && hongbao.endTs >= 0) {
        // 显示该红包
        console.log("现在显示的红包:" + hongbao.id);
    }

    // 未开始
    if (hongbao.startTs > 0 && hongbao.startTs < 3600 * 24) {
        setTimeout(function (hb) {
            return (function () {
                // 显示该红包
                console.log("显示红包:" + hb.id);
            })
        }(hongbao), (hongbao.startTs * 1000));
    }

    // 未结束
    if (hongbao.endTs > 0 && hongbao.endTs < 3600 * 24) {
        setTimeout(function (hb) {
            return (function () {
                // 隐藏该红包
                console.log("隐藏红包:" + hb.id);
            })
        }(hongbao), (hongbao.endTs * 1000));
    }
}

输出结果

现在显示的红包:1
隐藏红包:1
显示红包:2
隐藏红包:2
显示红包:3
隐藏红包:3


嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表

回复 路人甲 2016-08-05 16:46:35
无意闯入您的博客,写的挺好的。可是不填邮箱,就不能评论。。
回复 康哥 2016-08-07 20:10:37
回复路人甲: 哈哈哈,恩,主要是怕需要交流,而没有通知给留言的人。
回复 路人甲 2016-08-07 21:25:43
回复康哥: 兄台在哪儿高就啊
回复 康哥 2016-08-11 09:12:45
回复路人甲: 在阿里做社区,欢迎来这里逛逛 https://yq.aliyun.com/
回复 路人甲 2016-08-11 09:32:06
回复康哥: 很厉害啊
回复 康哥 2016-08-12 21:42:55
回复路人甲: 别这么说,大家相互学习。