Javascript 闭包详解及实例代码


Posted in Javascript onNovember 30, 2016

Javascript 闭包

闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它。因此,本文不会对闭包的概念进行大篇幅描述,直接上干货,让你分分钟学会闭包!

1 闭包,一睹为快

在接触一个新技术的时候,我首先会做的一件事就是找它的 demo code。对于我们来说,看代码比自然语言更能理解一个事物的本质。其实,闭包无处不在,比如:jQuery、zepto的核心代码都包含在一个大的闭包中,所以下面我先写一个最简单最原始的闭包,以便让你在大脑里产生闭包的画面:

function A(){
  function B(){
    console.log("Hello Closure!");
  }
  return B;
}
var C = A();
C();//Hello Closure!

这是最简单的闭包。

有了初步认识后,我们简单分析一下它和普通函数有什么不同,上面代码翻译成自然语言如下:

(1)定义普通函数 A

(2)在 A 中定义普通函数 B

(3)在 A 中返回 B

(4)执行 A, 并把 A 的返回结果赋值给变量 C

(5)执行 C

把这5步操作总结成一句话就是:

函数A的内部函数B被函数A外的一个变量 c 引用。

把这句话再加工一下就变成了闭包的定义:

当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。

因此,当你执行上述5步操作时,就已经定义了一个闭包!

这就是闭包。

2 闭包的用途

在了解闭包的作用之前,我们先了解一下 Javascript 中的GC机制:

在 Javascript 中,如果一个对象不再被引用,那么这个对象就会被 GC 回收,否则这个对象一直会保存在内存中。

在上述例子中,B 定义在 A 中,因此 B 依赖于 A ,而外部变量 C 又引用了 B , 所以A间接的被 C 引用。

也就是说,A 不会被 GC 回收,会一直保存在内存中。为了证明我们的推理,上面的例子稍作改进:

function A(){
  var count = 0;
  function B(){
    count ++;
    console.log(count);
  }
  return B;
}
var C = A();
C();// 1
C();// 2
C();// 3

count 是函数A 中的一个变量,它的值在函数B 中被改变,函数B 每执行一次,count 的值就在原来的基础上累加 1 。因此,函数A中的 count 变量会一直保存在内存中。

当我们需要在模块中定义一些变量,并希望这些变量一直保存在内存中但又不会“污染”全局的变量时,就可以用闭包来定义这个模块。

 3 高端写法

上面的写法其实是最原始的写法,而在实际应用中,会将闭包和匿名函数联系在一起使用。下面就是一个闭包常用的写法:

(function(document){
  var viewport;
  var obj = {
    init:function(id){
      viewport = document.querySelector("#"+id);
    },
    addChild:function(child){
      viewport.appendChild(child);
    },
    removeChild:function(child){
      viewport.removeChild(child);
    }
  }
  window.jView = obj;
})(document);

这个组件的作用是:初始化一个容器,然后可以给这个容器添加子容器,也可以移除一个容器。

功能很简单,但这里涉及到了另外一个概念:立即执行函数。 简单了解一下就行,需要重点理解的是这种写法是如何实现闭包功能的。

可以将上面的代码拆分成两部分:(function(){}) 和 () , 第1个() 是一个表达式,而这个表达式本身是一个匿名函数,所以在这个表达式后面加 () 就表示执行这个匿名函数。

因此这段代码执行执行过程可以分解如下:

var f = function(document){
  var viewport;
  var obj = {
    init:function(id){
      viewport = document.querySelector("#"+id);
    },
    addChild:function(child){
      viewport.appendChild(child);
    },
    removeChild:function(child){
      viewport.removeChild(child);
    }
  }
  window.jView = obj;
};
f(document);

在这段代码中似乎看到了闭包的影子,但 f 中没有任何返回值,似乎不具备闭包的条件,注意这句代码:

window.jView = obj;

obj 是在函数 f 中定义的一个对象,这个对象中定义了一系列方法, 执行window.jView = obj 就是在 window 全局对象定义了一个变量 jView,并将这个变量指向 obj 对象,即全局变量 jView 引用了 obj . 而 obj 对象中的函数又引用了函数 f 中的变量 viewport ,因此函数 f 中的 viewport 不会被 GC 回收,viewport 会一直保存到内存中,所以这种写法满足了闭包的条件。

 4 简单的总结语

这是对闭包最简单的理解,当然闭包还有其更深层次的理解,这个就涉及的多了,你需要了解JS的执行环境(execution context)、活动对象(activation object)以及作用域(scope)和作用域链(scope chain)的运行机制。但作为初学者,暂时不必了解这些,有了简单的理解之后,一定要在实际项目中用起来,等你用的多了,对于闭包,你自然会有更深层次的理解!

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
javascript window对象属性整理
Oct 24 Javascript
jQuery AJAX回调函数this指向问题
Feb 08 Javascript
jQuery:节点(插入,复制,替换,删除)操作
Mar 04 Javascript
jQuery如何取id有.的值一般的方法是取不到的
Apr 18 Javascript
推荐4个原生javascript常用的函数
Jan 12 Javascript
js实现动画特效的文字链接鼠标悬停提示的方法
Mar 02 Javascript
详解微信小程序 template添加绑定事件
Jun 23 Javascript
Node.js爬取豆瓣数据实例分析
Mar 05 Javascript
JavaScript中 ES6变量的结构赋值
Jul 10 Javascript
vue中$nextTick的用法讲解
Jan 17 Javascript
Vue中Table组件Select的勾选和取消勾选事件详解
Mar 19 Javascript
详解vite+ts快速搭建vue3项目以及介绍相关特性
Feb 25 Vue.js
jQuery特殊符号转义的实现
Nov 30 #Javascript
Javascript 引擎工作机制详解
Nov 30 #Javascript
将JSON字符串转换成Map对象的方法
Nov 30 #Javascript
JS实现重新加载当前页面或者父页面的几种方法
Nov 30 #Javascript
JS实现重新加载当前页面
Nov 29 #Javascript
jQuery弹出div层过2秒自动消失
Nov 29 #Javascript
headjs实现网站并行加载但顺序执行JS
Nov 29 #Javascript
You might like
php使用NumberFormatter格式化货币的方法
2015/03/21 PHP
php变量与数组相互转换的方法(extract与compact)
2016/12/02 PHP
PHP实现移除数组中为空或为某值元素的方法
2017/01/07 PHP
PHP递归实现文件夹的复制、删除、查看大小操作示例
2017/08/11 PHP
PHP使用zlib扩展实现GZIP压缩输出的方法详解
2018/04/09 PHP
jquery可见性过滤选择器使用示例
2013/06/24 Javascript
nodejs 实现模拟form表单上传文件
2014/07/14 NodeJs
JavaScript及jquey实现多个数组的合并操作
2014/09/06 Javascript
浅谈JavaScript中的作用域和闭包问题
2015/07/07 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
详解Angular的内置过滤器和自定义过滤器【推荐】
2016/12/26 Javascript
Bootstrap 设置datetimepicker在屏幕上面弹出设置方法
2017/03/21 Javascript
使用 Node.js 对文本内容分词和关键词抽取
2017/05/27 Javascript
微信小程序swiper组件用法实例分析【附源码下载】
2017/12/07 Javascript
深入浅析Vue.js 中的 v-for 列表渲染指令
2018/11/19 Javascript
JSON是什么?有哪些优点?JSON和XML的区别?
2019/04/29 Javascript
vue实现数字动态翻牌的效果(开箱即用)
2019/12/08 Javascript
JavaScript 中判断变量是否为数字的示例代码
2020/10/22 Javascript
Python中模块string.py详解
2017/03/12 Python
pycharm下打开、执行并调试scrapy爬虫程序的方法
2017/11/29 Python
python 实现调用子文件下的模块方法
2018/12/07 Python
基于python实现自动化办公学习笔记(CSV、word、Excel、PPT)
2019/08/06 Python
Python OpenCV视频截取并保存实现代码
2019/11/30 Python
如何基于python测量代码运行时间
2019/12/25 Python
Jupyter Notebook 文件默认目录的查看以及更改步骤
2020/04/14 Python
Linux安装Python3如何和系统自带的Python2并存
2020/07/23 Python
html5贪吃蛇游戏使用63行代码完美实现
2013/06/25 HTML / CSS
美国最流行的男士时尚网站:Touch of Modern
2018/02/05 全球购物
char型变量中能不能存贮一个中文汉字
2015/07/08 面试题
工程力学专业自荐信范文
2014/03/17 职场文书
云南省召开党的群众路线教育实践活动总结会议新闻稿
2014/10/21 职场文书
2014年保洁工作总结
2014/11/24 职场文书
2015年助残日活动总结
2015/03/27 职场文书
信用卡收入证明范本
2015/06/12 职场文书
毕业设计工作总结
2015/08/14 职场文书
《勇者辞职不干了》上卷BD发售宣传CM公开
2022/04/08 日漫