干货分享:让你分分钟学会javascript闭包


Posted in Javascript onDecember 25, 2015

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

1、闭包--爱的初体验

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

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

这是史上最简单的闭包,不能再简单了,再简单就不是闭包了!

有了初步的认识后,我们简单分析一下它和普通函数有什么不同,这样我们才能从“茫茫人海”中一眼认出“她”。

上面代码翻译成自然语言如下:

  • (1)定义了一个普通函数A
  • (2)在A中定义了普通函数B
  • (3)在A中返回B(确切的讲,在A中返回B的引用)
  • (4)执行A(),把A的返回结果赋值给变量 c
  • (5)执行 c()

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

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

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

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

不要刻意去记住这个定义,我告诉你这个定义的目的是想让你理解上面的5步操作就是在阐述闭包的定义。

因此,当你执行了上述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、高端写法

上面的写法其实是最简单最原始的写法,而在实际应用中,没人这么玩,特别是在一些大型JS框架中更不会这么写。我之所以还要告诉你这种写法,是因为干扰因素越少越容易专注于一件事。下面我用常用的写法来写一个简单的demo组件:

(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(){})()  红色部分是一个表达式,而这个表达式本身是一个匿名函数,所以在这个表达式后面加()就表示执行这个匿名函数。

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

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回收,会一直保存到内存中,所以这种写法满足闭包的条件。

4、简单的总结语

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

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

Javascript 相关文章推荐
表单内同名元素的控制
Nov 22 Javascript
jQuery ui 1.7更新小结
Aug 15 Javascript
jQuery Ajax提交表单查询获得数据实例代码
Sep 19 Javascript
实现web打印的各种方法介绍及实现代码
Jan 09 Javascript
jQuery获取对象简单实现方法小结
Oct 30 Javascript
JavaScript跨平台的开源框架NativeScript
Mar 24 Javascript
URL的参数中有加号传值变为空格的问题(URL特殊字符)
Nov 04 Javascript
JavaScript之RegExp_动力节点Java学院整理
Jun 29 Javascript
vue 实现axios拦截、页面跳转和token 验证
Jul 17 Javascript
微信小程序登录按钮遮罩浮层效果的实现方法
Dec 16 Javascript
JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结
Jun 27 Javascript
详解Vue的ref特性的使用
Jan 24 Javascript
javascript生成img标签的3种实现方法(对象、方法、html)
Dec 25 #Javascript
谈谈我对JavaScript中typeof和instanceof的深入理解
Dec 25 #Javascript
JavaScript中Window对象的属性及事件
Dec 25 #Javascript
JavaScript字符串删除重复字符的方法
Dec 25 #Javascript
JavaScript如何实现在文本框(密码框)输入提示语
Dec 25 #Javascript
jquery实现图片预加载
Dec 25 #Javascript
基于jquery实现图片相关操作(重绘、获取尺寸、调整大小、缩放)
Dec 25 #Javascript
You might like
PHP 根据IP地址控制访问的代码
2010/04/22 PHP
php单例模式实现(对象只被创建一次)
2012/12/05 PHP
php浏览历史记录的方法
2015/03/10 PHP
Yii2实现增删改查后留在当前页的方法详解
2017/01/13 PHP
jquery列表拖动排列(由项目提取相当好用)
2014/06/17 Javascript
jQuery实现DIV层收缩展开的方法
2015/02/27 Javascript
浅谈jQuery中replace()方法
2015/05/13 Javascript
快速掌握WordPress中加载JavaScript脚本的方法
2015/12/17 Javascript
基于javascript实现彩票随机数生成(升级版)
2020/04/17 Javascript
基于BootStarp的Dailog
2016/04/28 Javascript
基于JQuery实现的跑马灯效果(文字无缝向上翻动)
2016/12/02 Javascript
jQuery实现级联下拉框实战(5)
2017/02/08 Javascript
BootStrap+Mybatis框架下实现表单提交数据重复验证
2017/03/23 Javascript
Koa从零搭建到Api实现项目的搭建方法
2019/07/30 Javascript
jQuery-App输入框实现实时搜索
2020/11/19 jQuery
微信小程序弹窗禁止页面滚动的实现代码
2020/12/30 Javascript
[44:39]2014 DOTA2国际邀请赛中国区预选赛 NE VS CNB
2014/05/21 DOTA
[03:24][TI9纪实] Dota奶爸
2019/08/22 DOTA
python基础教程之分支、循环简单用法
2016/06/16 Python
python调用API实现智能回复机器人
2018/04/10 Python
python:接口间数据传递与调用方法
2018/12/17 Python
解决Djang2.0.1中的reverse导入失败的问题
2019/08/16 Python
python实现XML解析的方法解析
2019/11/16 Python
纯CSS3实现自定义Tooltip边框涂鸦风格的教程
2014/11/05 HTML / CSS
详解移动端HTML5页面端去掉input输入框的白色背景和边框(兼容Android和ios)
2016/12/15 HTML / CSS
DVF官方网站:美国时装界尊尚品牌
2017/08/29 全球购物
空字符串(“”)和null的区别
2012/11/13 面试题
体育专业个人的求职信范文
2013/09/21 职场文书
测试工程师岗位职责
2013/11/28 职场文书
学校工作推荐信范文
2014/07/11 职场文书
个人创业事迹材料
2014/12/30 职场文书
2016年教师学习教师法心得体会
2016/01/20 职场文书
诚信高考倡议书
2019/06/24 职场文书
SQL实现LeetCode(177.第N高薪水)
2021/08/04 MySQL
使用GO语言实现Mysql数据库CURD的简单示例
2021/08/07 Golang
Python爬虫 简单介绍一下Xpath及使用
2022/04/26 Python