首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >闭包和计数器

闭包和计数器

作者头像
Chor
发布2019-11-07 19:37:20
1K0
发布2019-11-07 19:37:20
举报
文章被收录于专栏:前端之旅前端之旅

之前想不通的一道题—–主要是不知道思路怎么来的,为何会想到用闭包。本来打算就将原博客转载过来,但是刚刚重新审视这道题的时候,好像看到了以前没有发现的东西,有种恍然大悟的感觉,所以决定用自己的话来解释这道题的思路。

假如我们想制作一个计数器,每点击一次就加一,代码如下:

var counter = 0; //把计数器counter设置成全局变量
function add(){
return counter+=1;
}
add(); //1
add(); //2
add(); //此时counter=3

>>固然可以实现功能,但问题就在于其他语句也有可能会改动到counter,这样的计数器是不安全的。

如果把counter改为外部访问不到的局部变量呢?

function add(){
var counter=0;
counter+=1;
}
add(); //counter为1
add(); //counter为1
add(); //counter为1

>>固然保证了counter不会被其他语句影响到,但问题就在于每次调用函数都会重置counter,无法实现计数功能。

所以我们需要的counter应该满足:1.不会被重置;2.在函数内部

第2点容易满足,但是由上面的例子我们知道,如果单纯把counter写在一个函数里,则每次调用都会重置,所以我们定义这样一个嵌套函数:将counter放在父函数里,子函数作为操作counter的函数,每次我们只调用子函数。 但是,全局作用域是无法访问嵌套函数中的子函数的,所以我们必须将子函数作为闭包返回出来,使其暴露在全局作用域下。依照这个想法,代码如下:

var add = function(){
    var counter = 0;
    return function(){
        return (++counter);
    }
}
add()();   //counter为1
add()();   //counter为1
add()();   //counter为1

>>意思是把add函数(父函数)执行后返回的函数(子函数)执行一次(注意这里是两次执行)。但这样的问题在于:每次调用add()()时依然执行了一次父函数,结果就是依然重置了counter。

那么有没有办法让父函数只执行一次,仅在那一次初始化counter,之后每次都只通过执行子函数来操作counter呢? 可以用自执行函数来解决这个问题—–也就是通过自执行函数(而不是通过add())来调用父函数,在这一次调用初始化counter,之后将返回的子函数赋给add,通过调用add()来操作counter。

var add = (function(){
var counter = 0;
return function(){
return(++counter);
}
})(); 
//这里add已经是父函数的执行结果了,即add已经是返回的那个子函数了
add(); //counter为1
console.log(counter) //undefined
add(); //counter为2
console.log(counter) //undefined
add(); //counter为3
console.log(counter) //undefined

接下来就是闭包的知识了: 在每次调用闭包add——-即function(){return(++counter)时,由于add中存在自由变量counter,所以它必须到定义该函数时所在的那个作用域中去寻找该变量,也就是到父函数中去寻找。恰好父函数中有一个为0的counter可以被引用,所以这时候完成加一操作,counter变成1。注意,接下来我们尝试调用了console.log(counter),但是输出的是undefined,这说明了即使add函数执行后返回了值为1的counter,但是该返回值并不是返回到全局作用域中(不然不会输出undefined),而是覆盖了父函数中原来定义的counter,使counter变为1;第二次调用add函数依然同上,只是此时引用counter时,引用的是为1的counter,加1后变为2;同理第三次,引用的是为2的counter,加1后变为3。 基于这道题,我们不难看出使用闭包函数的好处:

1、缓存: 最显而易见的好处,就是可以实现数据缓存,我们可以把一个需要长期用到的变量作为相对于闭包函数的自由变量,在闭包函数里直接使用它。因此该自由变量只初始化一次,但却可以通过多次调用闭包函数来使用。这比起我们直接在闭包函数中定义初始化变量,多次调用则多次初始化的做法,效率更高。闭包函数常见的一种用途就是上面例子中的—–实现计数功能。

2、实现封装: 自由变量只能被闭包函数本身或者其子函数访问,而不能被闭包函数之外的函数访问。这就实现了面向对象的封装性,更安全更可靠。

参考: http://www.cnblogs.com/haidaojiege/p/7070560.html https://www.cnblogs.com/leoin2012/p/3978979.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档