Javascript闭包——懂不懂由你,反正我是懂了_WangJiangNan17214的博客-程序员宅基地

技术标签: js  


作者:  FrankFang  来源:  博客园  发布时间: 2011-11-16 22:08  阅读: 190112 次  推荐: 68    原文链接    [收藏]  
摘要:“如果你不能向一个六岁的孩子解释清楚,那么其实你自己根本就没弄懂。”好吧,我试着向一个27岁的朋友就是JS闭包(JavaScript closure)却彻底失败了。

  越来越觉得国内没有教书育人的氛围,为了弄懂JS的闭包,我使出了我英语四级吃奶的劲去google上搜寻着有关闭包的解释,当我看到stackoverflow上这一篇解答,我脑中就出现了一句话:就是这货没跑了!

  不才译文见下,见笑了。

  Peter Mortensen问:

就像老Albert所说的,“如果你不能向一个六岁的孩子解释清楚,那么其实你自己根本就没弄懂。”好吧,我试着向一个27岁的朋友就是JS闭包(JavaScript closure)却彻底失败了。

你们会怎么把它解释给一个充满好奇心的六岁孩子听呢?

注:我看过StackOverflow上给出的示例,但根本没用。

  Ali的回答:

  当function里嵌套function时,内部的function可以访问外部function里的变量。

function  foo(x) {
    
var  tmp  =  3 ;
    
function  bar(y) {
        alert(x 
+  y  +  ( ++ tmp));
    }
    bar(
10 );
}
foo(
2 )

  不管执行多少次,都会alert 16,因为bar能访问foo的参数x,也能访问foo的变量tmp。

  但,这还不是闭包。当你return的是内部function时,就是一个闭包。内部function会close-over外部function的变量直到内部function结束。

function  foo(x) {
     var  tmp  =  3 ;
    
return  function  (y) {
        alert(x 
+  y  +  ( ++ tmp));
    }
}
var  bar  =  foo( 2 );  //  bar 现在是一个闭包
bar( 10 );

  上面的脚本最终也会alert 16,因为虽然bar不直接处于foo的内部作用域,但bar还是能访问x和tmp。

  但是,由于tmp仍存在于bar闭包的内部,所以它还是会自加1,而且你每次调用bar时它都会自加1.

  (考虑到六岁这个限制:我们其实可以建立不止一个闭包方法,比如return它们的数组,也可以把它们设置为全局变量。它们全都指向相同的x和相同的tmp,而不是各自有一份副本。)

  注:现在来整点儿七岁的内容。

  上面的x是一个字面值(值传递),和JS里其他的字面值一样,当调用foo时,实参x的值被复制了一份,复制的那一份作为了foo的参数x。

  那么问题来了,JS里处理object时是用到引用传递的,那么,你调用foo时传递一个object,foo函数return的闭包也会引用最初那个object!

function  foo(x) {
var  tmp  =  3 ;
return  function  (y) {
    alert(x 
+  y  +  tmp);
    x.memb 
=  x.memb  ?  x.memb  1  :  1 ;
    alert(x.memb);
    }
}
var  age  =  new  Number( 2 );
var  bar  =  foo(age);  //  bar 现在是一个引用了age的闭包
bar(
10 );

  不出我们意料,每次运行bar(10),x.memb都会自加1。但需要注意的是x每次都指向同一个object变量——age,运行两次bar(10)后,age.memb会变成2.

  这和HTML对象的内存泄漏有关,呃,不过貌似超出了答题的范围。

  JohnMerlino 对Ali说:

  这里有一个不用return关键字的闭包例子:

function  closureExample(objID, text, timedelay) { 
    setTimeout(
function () { 
        document.getElementById(objID).innerHTML 
=  text; 
    }, timedelay); 

closureExample(‘myDiv’, ‘Closure is created’, 
500 );

  深夜1:37 John Pick这样回答:

  JS里的function能访问它们的:

  1. 参数

  2. 局部变量或函数

  3. 外部变量(环境变量?),包括

3.1 全局变量,包括DOM。

3.2 外部函数的变量或函数。

  如果一个函数访问了它的外部变量,那么它就是一个闭包。

  注意,外部函数不是必需的。通过访问外部变量,一个闭包可以维持(keep alive)这些变量。在内部函数和外部函数的例子中,外部函数可以创建局部变量,并且最终退出;但是,如果任何一个或多个内部函数在它退出后却没有退出,那么内部函数就维持了外部函数的局部数据。

  一个典型的例子就是全局变量的使用。

  mykhal这样回答:

  Wikipedia对闭包的定义是这样的:

In computer science, a closure is a function together with a referencing environment for the nonlocal names (free variables) of that function.

  从技术上来讲,在JS中,每个function都是闭包,因为它总是能访问在它外部定义的数据。

  Since scope-defining construction in Javascript is a function, not a code block like in many other languages, what we usually mean by closure in Javascript is a fuction working with nonlocal variables defined in already executed surrounding function.

  闭包经常用于创建含有隐藏数据的函数(但并不总是这样)。

var  db  =  ( function () {
//  创建一个隐藏的object, 这个object持有一些数据
//  从外部是不能访问这个object的
var  data  =  {};
//  创建一个函数, 这个函数提供一些访问data的数据的方法
return  function (key, val) {
    if  (val  ===  undefined) {  return  data[key] }  //  get
     else  {  return  data[key]  =  val }  //  set
    }
//  我们可以调用这个匿名方法
//  返回这个内部函数,它是一个闭包
})();

db(
' x ' );  //  返回 undefined
db(
' x ' 1 );  //  设置data['x']为1
db(
' x ' );  //  返回 1
//  我们不可能访问data这个object本身
//  但是我们可以设置它的成员

  看了这么多外国大牛的解答,不知道你懂还是不懂,反正我是懂了。

  P.S. 发布文章之后看到@xiaotie的一篇文章,觉得有必要推荐一下,因为其剖析得更为深入。有人说应该在文章结尾对闭包进行总结,可惜小弟才疏学浅,不能给出一个精辟的总结。

  @xiaotie对闭包的总结如下:

(1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的;

(2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的,如果需要知道闭包细节才能用好的话,这个闭包是设计失败的;

(3)尽量少学习。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/WangJiangNan17214/article/details/70761547

智能推荐

常用分类算法_inte_sleeper的博客-程序员宅基地_以下属于分类算法

分类算法通常需要经过两步:训练和分类。如下:训练:训练集——>特征选取——>训练——>分类器分类:新样本——>特征选取——>分类——>判决最初的数据挖掘分类应用大多都是在这些方法及基于内存基础上所构造的算法。目前数据挖掘方法都要求具有基于外存以处理大规模数据集合能力且具有可扩展能力。下面对几种主要的分类方法做个简要介绍:(1)决策树决策树归纳是经典的分类算法。它采用自顶

java swing jlist保存_在Swing Java中将元素添加到JList_weixin_39865866的博客-程序员宅基地

小编典典不要使用,实际上不要Thread.sleep(int)在期间使用EventDispashThread,因为睡眠锁定了当前电流Thread,在这种情况下EventDispashThread,它向GUI输出了异常输出,更多有关Swing的Concurency,如果需要处理,则将Items wrappend添加到中Runneble#Thread,将GUI的输出包装到中invokeLater,或者...

go-redis 缓存对象_Kotlin20180728的博客-程序员宅基地_go redis 存储对象

github.com/go-redis/redis缓存对象package mainimport ( "context" "github.com/davecgh/go-spew/spew" "github.com/go-redis/redis/v8")type Model struct { Str1 string `redis:"str1"` Str2 string `redis:"str2"` Int int `redis:"int"` Bo

揭秘:三国时能令诸葛亮自叹不如的奇才是谁?_weixin_30919429的博客-程序员宅基地

核心提示:雄才大略的诸葛亮在三国的江湖中笑傲群英,能入他法眼的人才委实不多。然而,有一个非常厉害的奇才,诸葛亮对之非常看重。雄才大略的诸葛亮在三国的江湖中笑傲群英,能入他法眼的人才委实不多。然而,有一个非常厉害的奇才,诸葛亮对之非常看重,不仅费尽周折将其网罗至刘备麾下,而且由衷地公开称赞说这个人比自己强:“运筹策于帷幄之中,吾不如子初远矣。”(见《三国志·蜀书·刘巴传》裴松之注)诸葛...

ssm分页_xuesibianxing的博客-程序员宅基地_ssm分页

页面用bootstrapTable实现(配置查询的参数即可),前提得引入bootstrapTable的css,jsfunction load() { var typeid = $("#typeid").val(); $('#exampleTable').bootstrapTable({ method : 'get', // 服务器数据的请求方式 get or post ...

攻防世界 misc 高手区 Miscellaneous-300_IOT秋风的博客-程序员宅基地

解题过程下载下来是一个zip密码不知道,不是伪加密爆破密码emmm密码是里面的压缩包名,根据提示套娃了import zipfileimport rezipname = "C:\\Users\\13957\\Desktop\\"+"47096.zip"while True: if zipname != "C:\\Users\\13957\\Desktop\\73168.zip": ts1 = zipfile.ZipFile(zipname) res

随便推点

Observer_Seric.的博客-程序员宅基地

Observer的功能 负责把data选项中的属性转换成响应式数据 data中的某个属性也是对象,把该属性转换成响应式数据(例如data中的某个属性为Student对象,也要将Student对象中的属性转换成响应式) 数据变化发送通知 observer.js文件中的基本代码如下:class Observer { constructor(data) { this.walk(data); } walk(data) { //1、判断data是否是对象...

Linuxshell脚本之if条件判断_weixin_30580943的博客-程序员宅基地

复制代码 代码如下: if list then do something here elif list then do another thing here else do something else here fi EX1:复制代码 代码如下:#!/bin/shSYST...

[转]资料管理软件_weixin_30662011的博客-程序员宅基地

[转]资料管理软件 --sunfruit整天和电脑打交道,信息资料随着时间的推移也积累的越来越多,直到从资料里面找到所需的资料越来越难,于是就编写了一个资料管理软件,用于管理日常资料说明:数据库:在数据的存储方面为了方便,使用了AccessJDK :使用的JDK版本是1.5相关说明:...

Redis 主从复制-哨兵-集群 相关部署_W.scaler的博客-程序员宅基地

Redis 主从复制+哨兵+集群一.主从复制-哨兵-集群二.主从复制1.主从复制的作用2.主从复制流程3.部署Redis 主从复制三.哨兵模式1.哨兵模式的原理2.哨兵模式的作用3.哨兵结构由两部分组成,哨兵节点和数据节点部署哨兵模式四.集群模式1.集群的作用,可以归纳为两点2.Redis集群的数据分片3.以3个节点组成的集群为例4.Redis集群的主从复制模型5.Redis集群部署一.主从复制-哨兵-集群1.主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复

IIS 7 中设置文件上传大小限制设置方法_记得微笑的博客-程序员宅基地

有时候我们需要限制上传文件的大小,那么可以参考下面的方法在IIS 6.0中设置文件上传大小的方法,就是配置如下节点:复制代码 代码如下:        但在IIS7中,设置如上设置后,不管设置多大数值,最大上传了限制为30M还要进行如下设置才能正确:方法1:appcmd set config "My Site/MyApp

推荐文章

热门文章

相关标签