1. 诡异的闭包

javascript 中有一个特殊的特性 - 闭包,对于 .NET 程序员来说,比较熟悉的是面向对象的程序设计 OOP,  而来自函数式语言的闭包则显得比较诡异,许多程序员对它敬而远之。

对于闭包我们还是要从函数式语言的特点说起。

不知道你有没有发现,在 javascript 中没有 public ,private 之类的关键字,也没有 class ,虽然也存在对象一说,但是对象的地位远远没有在 C# 中是一等公民,在 js 中,没有对象你也可以一样写程序。它只是一种数据的表示形式而已,可有也可无。

2. 闭包何来?

如何在 javascript 实现数据的保护呢?闭包就是实现它的利器,这需要我们放下普通的对象,理解一下 javascript 的工作原理。

在 javascript 中,可以在函数中定义新的函数,这种嵌套函数还可以作为函数的返回值,被外部的变量所引用。在普通的程序设计语言中,比如 C 中,虽然也存在函数指针的概念,但是,所谓的函数指针仅仅是一段代码的地址而已,而 javascript 中返回的函数引用,则不限于此。

在 C 语言中,在函数运行的时候,局部变量是保存在堆栈中的,函数执行完毕,系统所做的是弹出堆栈。

实际上,在 javascript 中,函数每次执行的时候,注意是运行时,系统会同时创建一个此次函数运行的环境对象,而此次运行期间的局部变量则关联在这个环境对象上,在普通不返回函数的普通函数中,函数执行完毕,则环境对象也一起释放。而如果函数返回了定义在外部函数中的嵌套函数,那么,这个环境对象将不会释放,也就是说,这个时候,返回了一个看得见的函数对象,还附带了一个看不见的暗物质 - 外部函数的环境对象。

看得见的函数对象加上隐含的环境对象就是闭包。

这个环境对象只能通过这个函数隐式访问,我们并没有它的引用,也无法直接访问它。结果就是实现了信息的隐藏。

3. 实现私有的数据

考虑下面的代码

function outer() {var name = "Alice";var inner = function () {return name;}return inner;
}var fn = outer();
alert(fn());

在这个例子中,看起来简单的 fn 函数背后,其实暗藏了在执行 outer 函数时期创建的环境对象,所以通过 fn 可以得到 Alice 这个名字,而且没有其他的渠道允许得到这个名字。

4. 为什么数据搞乱了?

再看另外一个经典的例子。

<body><div><a href="#">Click Me!</a><a href="#">Click Me!</a><a href="#">Click Me!</a></div><script type ="text/javascript">function main(links) {for (var i = 0; i < links.length; i++) {links[i].onclick = function () {alert(i + 1);}}};main(document.getElementsByTagName("a"));</script></body>

弹出的是多少呢?感觉有三次循环,应该弹出 1, 2, 3。运行一下,你会看到实际上是 4, 4, 4!

是不是非常诡异?

从闭包的角度来说,则非常简单,main 函数执行了几次呢?只有一次,在执行的时候创建了一个闭包对象,其中引用了定义在 main 中的局部变量 i,在循环体中,实际上创建了三个内部函数,它们引用的都是同一个环境对象。这些函数注册到链接的 onclick 事件上,其实也就是已经传出了函数 main,所以,main 的环境对象也就悄悄地成为了暗物质,而循环完成之后 i 已经最终被赋予了 3 这个值,三个函数访问的是同一个环境对象中的 i, 所以,在点击链接的时候看到 4 这个结果也就正常了。

5. 解铃还需系铃人

如果希望得到的是  1, 2, 3 这个结果又该怎么办呢?

我们可以定义一个内部函数,让它执行三次,这个将会创建三个对应的环境对象,我们可以使得这三个环境对象包含不同的值。

function main(links) {var inner = function (elem, i) {elem.onclick = function () {alert(i + 1);};};for (var i = 0; i < links.length; i++) {var elem = links[i];inner(elem, i);}
};

由于 inner 函数执行了三次,所以将会创建三个不同的环境对象,每个环境对象中的  i 都是不同的值。这样注册到 onclick 中的函数就可以访问到不同的值了。

闭包的概念

这里,我们可以看一下闭包的概念了。来自 Wiki 的说明是这样的

在计算机科学中,闭包Closure)是词法闭包Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

转载于:https://www.cnblogs.com/haogj/archive/2012/11/28/2793535.html

javascript 中的暗物质 - 闭包相关推荐

  1. JavaScript中的作用域,闭包和上下文

    深入理解JavaScript中的作用域和上下文 很多语言当中都会有作用域的概念,它会给我们带来便利,偶尔也会有烦恼,只有清楚地理解和掌握了它,才能更好地为我所用,今天就带来这么一篇文章供大家参考. 介 ...

  2. javascript中重要概念-闭包-深入理解

    在上次的分享中javascript--函数参数与闭包--详解,对闭包的解释不够深入.本人经过一段时间的学习,对闭包的概念又有了新的理解.于是便把学习的过程整理成文章,一是为了加深自己闭包的理解,二是给 ...

  3. [转]在Javascript中闭包(Closure)

    转载自: http://baike.baidu.com/view/648413.htm 一.什么是闭包? "官方"的解释是:所谓"闭包",指的是一个拥有许多变量 ...

  4. 在Javascript中闭包(Closure)

    一.什么是闭包? "官方"的解释是:所谓"闭包",指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 相 ...

  5. javascript中的闭包这一篇就够了

    什么是闭包 维基百科中的概念 在计算机科学中,闭包(也称词法闭包或函数闭包)是指一个函数或函数的引用,与一个引用环境绑定在一起,这个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表. 闭包, ...

  6. 让你分分钟学会Javascript中的闭包

    Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...

  7. javascript中闭包的一些理解

    闭包是javascript中绕不开的话题,关于闭包的一些概念和应用,这方面资料比较多,在此就不再赘述.众所周知,闭包的一个作用就是 让一些变量始终保持在内存中 ,在此我用一些实际代码对这句话作进一步的 ...

  8. Javascript中闭包的作用域链

    作用域定义了在当前上下文中能够被访问到的成员,在Javascript中分为全局作用域和函数作用域,通过函数嵌套可以实现嵌套作用域. 闭包一般发生在嵌套作用域中.闭包是JavaScript最强大的特性之 ...

  9. javascript中关于作用域和闭包

    列表项目 前言 学习了javascript已经很久了,关于这个语言中的这两个特性也是早已耳熟能详,但是在实际的使用的过程中或者是遇到相关的问题的时候,还是不能很好的解决. 因此我觉得很有必要深入的学习 ...

最新文章

  1. 学术-数学:哥德巴赫猜想
  2. 【iBoard 电子学堂 / iCore核心板教程】【verilog / modelsim 基础例程】
  3. (Oracle学习笔记) Oracle体系结构
  4. 解决appium-inspector连接后在Appium中报错:No route found for /sessions
  5. 2008安装完了找不到_7206BEP.进口轴承_玉溪SKF轴承安装指南
  6. 在Flex组件外观实施中使用Scale9
  7. 一年多少钱_赴英读研一年多少钱?
  8. java 下载速度计算_测量Java下载速度
  9. redis基础知识——菜鸟教程
  10. 基于java小区物业管理系统(含源文件)
  11. c语言变量ppt,C语言数据类型和变量课件PPT
  12. 阿里巴巴android代码生成器,在线热点代码生成器代码生成工具-1秒钟美工助手官方网站...
  13. swiper / 移动端触摸滑动插件 / 手机轮播插件
  14. Android——距离传感器(PROXIMITY)的应用
  15. OPEN-SET RECOGNITION:A GOOD CLOSED-SET CLASSIFIER IS ALL YOU NEED
  16. 计算机硬盘正常的使用步骤,500g的硬盘的电脑合理分区方法
  17. 《那一夜》———孙溟㠭书画
  18. openstack单节点安装(先电版)
  19. acwing基础课——堆
  20. <iomanip>库

热门文章

  1. MySQL 8.0 压缩包版安装方法
  2. NLog日志框架使用探究
  3. UTC时间、GMT时间、本地时间、Unix时间戳
  4. 社交中的黄金法则,你要细细体会品味
  5. oracle 11g重新安装配置,Oracle 11g数据库安装和卸载教程
  6. java 匹配mysql按钮_使用Java在mysql查询中设置匹配函数
  7. Linux统计单个文件统计
  8. Java线程之多线程与多进程(1)——以操作系统的角度述说线程与进程
  9. xd可以用ui动效效果吗_通过动画使UI设计栩栩如生:Adobe XD和After Effects
  10. 毕业年限不长的前端焦虑和突破方法