如何正确理解闭包

如何正确理解闭包先看下下列代码var Closure = function() {console.log); // 输出 3这段代码中,C

大家好,欢迎来到IT知识分享网。如何正确理解闭包"

想必身为前端开发,大家对“闭包”一词并不陌生,但能真正理解闭包概念,并能熟练使用闭包却是成为了判断前端技术水平的一个硬性标准。很多刚入行的前端,就因为对闭包概念理解不是很透彻,导致大家在面试阶段屡屡碰壁,惨遭pass。那今天我带大家深入理解下关于闭包的概念。

先看下下列代码

var   Closure =   function()   {
  var   count   =   0;
  var   get   =   function()   {
    count   ++;
    return   count;
  };
  return   get;};var   counter   =   Closure ();
console.log(counter());   //   输出   1
console.log(counter());   //   输出   2
console.log(counter());   //   输出   3

这段代码中,Closure () 函数中有一个局部变量count,初值为 0。还有一个叫做 get 的函数,get 将其父作用域,也就是Closure () 函数中的 count变量增加 1,并返回 count 的值。Closure () 的返回值是 get 函数。在外部我们通过 counter变量调用了Closure () 函数并获取了它的返回值,也就是 get 函数,接下来反复调用几次 counter(),我们发现每次返回的值都递增了1。

让我们看看上面的例子有什么特点,按照通常命令式编程思维的理解,count 是Closure 函数内部的变量,它的生命周期就是Closure 被调用的时期,当Closure 从调用栈中返回时,count 变量申请的空间也就被释放。问题是,Closure () 调用结束后,counter() 却引用了“已经释放了的” count变量,而且非但没有出错,反而每次调用 counter() 时还修改并返回了 count。这是怎么回事呢?

这正是所谓闭包的特性。当一个函数返回它内部定义的一个函数时,就产生了一个闭包,闭包不但包括被返回的函数,还包括这个函数的定义环境。上面例子中,当函数Closure () 的内部函数 get 被一个外部变量 counter 引用时,counter 和Closure ()的局部变量就是一个闭包。如果还不够清晰,下面这个例子可以帮助你理解:

var   Closure =   function()   {
  var   count   =   0;
  var   get   =   function()   {
    count   ++;
    return   count;
  };
  return   get;};
var   counter1   =   Closure ();
var   counter2   =   Closure ();
console.log(counter1());   //   输出   1
console.log(counter2());   //   输出   1
console.log(counter1());   //   输出   2
console.log(counter1());   //   输出   3
console.log(counter2());   //   输出   2

上面这个例子解释了闭包是如何产生的:counter1和counter2分别调用了Closure() 函数,生成了两个闭包的实例,它们内部引用的 count 变量分别属于各自的运行环境。我们可以理解为,在Closure () 返回 get 函数时,私下将 get 可能引用到的Closure () 函数的内部变量(也就是 count 变量)也返回了,并在内存中生成了一个副本,之后Closure () 返回的函数的两个实例 counter1和 counter2 就是相互独立的了。

那闭包有什么样的用途呢?其实闭包有两个主要用途,一是实现嵌套的回调函数,二是隐藏对象的细节。

我们知道,JavaScript 的对象没有私有属性,也就是说对象的每一个属性都是曝露给外部的。这样可能会有安全隐患,譬如对象的使用者直接修改了某个属性,导致对象内部数据的一致性受到破坏等。JavaScript通过约定在所有私有属性前加上下划线,表示这个属性是私有的,外部对象不应该直接读写它。但这只是个非正式的约定,假设对象的使用者不这么做,有没有更严格的机制呢?答案是有的,通过闭包可以实现。让我们再看看前面那个例子:

var  Closure   =   function()   {
  var   count   =   0;
  var   get   =   function()   {
    count   ++;
    return   count;
  };
  return   get;
};
var   counter   =   Closure ();
console.log(counter());   //   输出   1
console.log(counter());   //   输出   2
console.log(counter());   //   输出   3

我们可以看到,只有调用counter() 才能访问到闭包内的 count 变量,并按照规则对其增加1,除此之外决无可能用其他方式找到 count 变量。受到这个简单例子的启发,我们可以把一个对象用闭包封装起来,只返回一个“访问器”的对象,即可实现对细节隐藏。

通过以上demo,我希望能够对大家理解闭包有所帮助。

往期推荐:

JS数据类型之字符串篇

JS 的5个不良编码习惯,现在就改掉吧

我写CSS的常用套路

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/61703.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信