一分钟理解js闭包


Posted in Javascript onMay 04, 2016

什么是闭包?
先看一段代码:

function a(){
  var n = 0;
  function inc() {
    n++;
    console.log(n);
  }
  inc(); 
  inc(); 
}
a(); //控制台输出1,再输出2

简单吧。再来看一段代码:

function a(){
  var n = 0;
  this.inc = function () {
    n++; 
    console.log(n);
  };
}
var c = new a();
c.inc();  //控制台输出1
c.inc();  //控制台输出2

简单吧。

什么是闭包?这就是闭包!

有权访问另一个函数作用域内变量的函数都是闭包。这里 inc 函数访问了构造函数 a 里面的变量 n,所以形成了一个闭包。

再来看一段代码:

function a(){
  var n = 0;
  function inc(){
    n++; 
    console.log(n);
  }
  return inc;
}
var c = a();
c();  //控制台输出1
c();  //控制台输出2

看看是怎么执行的:

var c = couter(),这一句 couter()返回的是函数 inc,那这句等同于 var c = inc;

c(),这一句等同于 inc();  注意,函数名只是一个标识(指向函数的指针),而()才是执行函数。

后面三句翻译过来就是:  var c = inc;  inc();  inc();,跟第一段代码有区别吗? 没有。

什么是闭包?这就是闭包!

所有的教科书教程上都喜欢用最后一段来说明闭包,但我觉得这将问题复杂化了。这里面返回的是函数名,没看过谭浩强C/C++程序设计的同学可能一下子没反应出带不带()的区别,也就是说这种写法自带一个陷阱。虽然这种写法更显高大上,但我还是喜欢将问题单一化,看看代码 1 和代码 2,你还会纠结函数的调用,你会纠结 n 的值吗?

一分钟理解js闭包

为啥要这样写?
我们知道,js的每个函数都是一个个小黑屋,它可以获取外界信息,但是外界却无法直接看到里面的内容。将变量 n 放进小黑屋里,除了 inc 函数之外,没有其他办法能接触到变量 n,而且在函数 a 外定义同名的变量 n 也是互不影响的,这就是所谓的增强“封装性”。

而之所以要用 return 返回函数标识 inc,是因为在 a 函数外部无法直接调用 inc 函数,所以 return inc 与外部联系起来,代码 2 中的 this 也是将 inc 与外部联系起来而已。

常见的陷阱
看看这个:

function createFunctions(){
  var result = new Array();
  for (var i=0; i < 10; i++){
    result[i] = function(){
      return i;
    };
  }
  return result;
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
  console.log(funcs[i]());
}

乍一看,以为输出 0~9 ,万万没想到输出10个10?

这里的陷阱就是:函数带()才是执行函数! 单纯的一句 var f = function() { alert('Hi'); }; 是不会弹窗的,后面接一句 f(); 才会执行函数内部的代码。上面代码翻译一下就是:

var result = new Array(), i;
result[0] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
result[1] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
...
result[9] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
i = 10;
funcs = result;
result = null;

console.log(i); // funcs[0]()就是执行 return i 语句,就是返回10
console.log(i); // funcs[1]()就是执行 return i 语句,就是返回10
...
console.log(i); // funcs[9]()就是执行 return i 语句,就是返回10

为什么只垃圾回收了 result,但却不收了 i 呢? 因为 i 还在被 function 引用着啊。好比一个餐厅,盘子总是有限的,所以服务员会去巡台回收空盘子,但还装着菜的盘子他怎么敢收? 当然,你自己手动倒掉了盘子里面的菜(=null),那盘子就会被收走了,这就是所谓的内存回收机制。

至于 i 的值怎么还能保留,其实从文章开头一路读下来,这应该没有什么可以纠结的地方。盘子里面的菜,吃了一块不就应该少一块吗?

总结一下
闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!另外使用闭包也要注意变量的值是否符合你的要求,因为他就像一个静态私有变量一样。闭包通常会跟很多东西混搭起来,接触多了才能加深理解,这里只是开个头说说基础性的东西。

本文链接:http://www.cnblogs.com/qieguo/p/5457040.html

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
网络图片延迟加载实现代码 超越jquery控件
Mar 27 Javascript
JS截取字符串实例详解
Nov 24 Javascript
基于JS2Image实现圣诞树代码
Dec 24 Javascript
jquery获取点击控件的绝对位置简单实例
Oct 13 Javascript
jQuery实现手机上输入后隐藏键盘功能
Jan 04 Javascript
Extjs表单输入框异步校验的插件实现方法
Mar 20 Javascript
JavaScript数据结构之单链表和循环链表
Nov 28 Javascript
js中this对象用法分析
Jan 05 Javascript
你可能不知道的前端算法之文字避让(inMap)
Jan 12 Javascript
vue生命周期与钩子函数简单示例
Mar 13 Javascript
vue实现可视化可拖放的自定义表单的示例代码
Mar 20 Javascript
微信小程序 (地址选择1)--选取搜索地点并显示效果
Dec 17 Javascript
学JavaScript七大注意事项【必看】
May 04 #Javascript
Jquery ui datepicker设置日期范围,如只能隔3天【实现代码】
May 04 #Javascript
开启BootStrap学习之旅
May 04 #Javascript
JavaScript入门教程之引用类型
May 04 #Javascript
javascript和jquery实现用户登录验证
May 04 #Javascript
基于Bootstrap使用jQuery实现简单可编辑表格
May 04 #Javascript
纯JS代码实现气泡效果
May 04 #Javascript
You might like
PHP 获取远程文件内容的函数代码
2010/03/24 PHP
关于laravel 日志写入失败问题汇总
2019/10/17 PHP
JQuery AJAX实现目录浏览与编辑的代码
2008/10/21 Javascript
使用jquery实现图文切换效果另加特效
2013/01/20 Javascript
javascript常用对话框小集
2013/09/13 Javascript
手机端js和html5刮刮卡效果
2020/09/29 Javascript
js异步编程小技巧详解
2017/08/14 Javascript
Vue-cli中为单独页面设置背景色的实现方法
2018/02/11 Javascript
Angular路由ui-router配置详解
2018/08/01 Javascript
nodejs对项目下所有空文件夹创建gitkeep的方法
2019/08/02 NodeJs
vue基于better-scroll仿京东分类列表
2020/06/30 Javascript
[06:06]2018DOTA2亚洲邀请赛主赛事第四日战况回顾 全明星赛欢乐上演
2018/04/07 DOTA
[49:08]完美世界DOTA2联赛PWL S2 LBZS vs FTD.C 第一场 11.27
2020/12/01 DOTA
举例详解Python中的split()函数的使用方法
2015/04/07 Python
Python中的FTP通信模块ftplib的用法整理
2016/07/08 Python
Python基于tkinter模块实现的改名小工具示例
2017/07/27 Python
Python语言实现将图片转化为html页面
2017/12/06 Python
python正则中最短匹配实现代码
2018/01/16 Python
Django 限制用户访问频率的中间件的实现
2018/08/23 Python
python使用pygame框架实现推箱子游戏
2018/11/20 Python
python学习——内置函数、数据结构、标准库的技巧(推荐)
2019/04/18 Python
Python如何爬取微信公众号文章和评论(基于 Fiddler 抓包分析)
2019/06/28 Python
Python reshape的用法及多个二维数组合并为三维数组的实例
2020/02/07 Python
appium+python adb常用命令分享
2020/03/06 Python
使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
2020/07/02 Python
基于python实现操作redis及消息队列
2020/08/27 Python
Html5移动端获奖无缝滚动动画实现示例
2018/06/25 HTML / CSS
Sunglass Hut巴西网上商店:男女太阳镜
2020/10/04 全球购物
留学自荐信的技巧
2013/10/17 职场文书
思想政治教育专业个人求职信范文
2013/12/20 职场文书
学生会主席事迹材料
2014/01/28 职场文书
教师党员承诺书
2014/03/25 职场文书
驾驶员安全责任协议书
2016/03/22 职场文书
深度好文:50条没人告诉你的人生经验,句句精辟
2019/08/22 职场文书
总结高并发下Nginx性能如何优化
2021/11/01 Servers
mysql 8.0.27 绿色解压版安装教程及配置方法
2022/04/20 MySQL