初学闭包时一直以为很简单。但伴随对一个问题深入学习后,才算真正理解了闭包,同时也发现连<<JavaScript高级程序设计>>中都些不准确的地方。

我不准备从头介绍闭包的概念,而是在下面列了几份参考资料。其中以【参考2】最为简洁,本文也是因文中的习题而引出进一步的探讨。

从[参考2]最后提出的习题开始(应该来自<<JavaScript高级 程序设计>> 7.2),期望下面的程序可以输出"My Object",并且预期在取得this.name值时的标识符解析(identifier resolution)顺序如下:

(示例1)

上面程序会在log位置输出"The Window", 而不是期望的"My Object"。

其实红色部分错了。this并不指向创建它的对象,而是指向执行它的对象。
所以在执行下面这句话时,this其实是全局的window:

object.getNameFunc()();

这句话等价于以下两句:

vartempFunc = object.getNameFunc();

tempFunc();

它的执行对象就是全局的window,并且tempFunc和window.tempFunc完全等价的。

其执行对象的变化示意如下:

getNameFunc的执行对象是object, 而返回的闭包函数的执行对象是window。

增加一个示例,可以更明确的了解到这一点:
var name = "The Window";

var object = {

 name : "My Object",

getNameFunc:function() {

console.log(this.name);  // The Window

}

};

window.onload = object.getNameFunc;

(示例2)

所以如果要达成期望的输出,必须改变this的指向。有两种做法:
  1. 不用this,而使用参数从父函数传入所需的数据。(不用this,不是简单将this去除。默认还是会使用this访问的。)
  2. 显示改变this 指向 (比如call或apply)。

第一种方法的示例:

var name ="The Window";

var object = {

  name :"My Object",

getNameFunc:function() {

var that =this;

return function(){

return that.name;

};

}

 };

 console.log( window.object.getNameFunc()());

(示例3)

第二种方法的示例:
  1. 将调用方法改为如下:

console.log( object.getNameFunc().call(object) );

2. 简化调用,改为如下:

var name ="The Window";

var object = {

    name : "My Object",

getNameFunc:function() {

return(function(){

returnthis.name;

}).call(this);

}

 };

console.log( object.getNameFunc());

(示例4)

到底发生了什么?

<<JavaScript高级程序设计>>:
当 某个函数第一次被调用时,会创建一个执行环境(execution context,环境比上下文更直白)及相应的作用域链(scope chain),并把作用域(scope)赋值给一个特殊的内部属性([[Scope]])。然后,使用this、arguments和其它命名参数的值来 初始化函数的活动对象(activation object)。但在作用域链中,外部函数(outer)的活动对象(activation object)处于第二位,外部函数的外部函数的活动对象处于第三位,……直至作为作用域链终点的全局执行环境。(7.2, 3rd Edition)

执行环境包含了三个部分 [详细内容在【参考4】中]:
  a. 词法环境
  b. 变量环境
  c. ThisBinding

(图片来自【参考4】)

如果这样,示例的理解就应该是正确!所以,显然不是这么单纯。再思考一下函数的创建时机。函数的声明与其实例化(instantiation)的时间是不同的,而是在使用时创建。实例化过程中发生了什么?

[参考5]中给的解释:  与外部函数声明对应的函数对象会在全局执行环境的变量实例化过程中被创建。因此,外部函数对象的 [[scope]] 属性中会包含一个只有全局对象的“单项目(one item)”作用域链。
这样就对了。下面就是name的查找顺序(和示例1的this.name不同)。

如下面的示例所示:

var name ="The Window";

var object = {

  name :"My Object",

getNameFunc:function() {

var name="Inner Of getNameFunc";

return function(){

console.log(name); //Inner Of getNameFunc

return name;

};

}

 };

 console.log( window.object.getNameFunc()()); //Inner Of getNameFunc

(示例5)

References:
1. PPK 谈 JavaScript 的 this 关键字
 http://www.cnblogs.com/georgewing/archive/2009/09/29/1576641.html
2. 学习Javascript闭包(Closure)
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
3.  闭包的秘密
http://www.gracecode.com/archives/2385/
4. JavaScript Closures Explained
 http://lostechies.com/derekgreer/2012/02/17/javascript-closures-explained/
5. 理解JavaScript闭包
 http://www.cn-cuckoo.com/main/wp-content/uploads/2007/08/JavaScriptClosures.html

转载于:https://www.cnblogs.com/lijie33402/p/4571263.html

【javascript闭包】转载一篇不错的解释,也有几个大牛的链接相关推荐

  1. 转载一篇不错的文章:谈谈“野生”Java程序员学习的道路

    逛论坛看到的一篇不错的文章,特此转载:本文转载自:左潇龙  原文链接:点击打开链接 引言 很尴尬的是,这个类型的文章其实之前笔者就写过,原文章里,笔者自称LZ(也就是楼主,有人说是老子的简写,笔者只想 ...

  2. 理解 JavaScript 闭包{转载}

    本文转载自:http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html 要成为高级 JavaScript 程序 ...

  3. 再看《周渔的火车》 转载一篇不错的影评

    今天又看了一遍<周渔的火车>,果然跟之前看的感觉不同.那时唯一的印象是周渔坐在车厢中,车窗的光影滑过她的脸. 这次居然看到了一个完美主义的超级自我的女人. 网上看了不少影评,转载一篇我认为 ...

  4. 转载一篇不错的介绍ORM框架的文章

    前言 在以前的一篇文章中,为大家分享了<什么是ORM?为什么用ORM?浅析ORM的使用及利弊>.那么,在目前的.NET(C#)的世界里,有哪些主流的ORM,SqlSugar,Dapper, ...

  5. 转载一篇不错的博客:程序员的幽默

    也是机缘巧合,让我一个之前工作从未接触过程序员的人,现在成天和程序员打交道,要知道,不懂技术,往往他们想和你幽默的搞笑一下,未必能读懂. 都说程序员情商低,不爱说话,比较闷骚.可是,只要你深入的接触下 ...

  6. 全面理解Javascript闭包和闭包的几种写法及用途--转载自https://www.cnblogs.com/yunfeifei/p/4019504.html...

    全面理解Javascript闭包和闭包的几种写法及用途 好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一 ...

  7. javascript闭包—围观大神如何解释闭包

    闭包的概念已经出来很长时间了,网上资源一大把,本着拿来主意的方法来看看. 这一篇文章 学习Javascript闭包(Closure) 是大神阮一峰的博文,作者循序渐进,讲的很透彻.下面一一剖析. 1. ...

  8. [转载]深入理解JavaScript闭包(closure)

    最近在网上查阅了不少Javascript闭包(closure)相关的资料,写的大多是非常的学术和专业.对于初学者来说别说理解闭包了,就连文字叙述都很难看懂.撰写此文的目的就是用最通俗的文字揭开Java ...

  9. javascript闭包_通过邮寄包裹解释JavaScript闭包

    javascript闭包 by Kevin Kononenko 凯文·科诺年科(Kevin Kononenko) 通过邮寄包裹解释JavaScript闭包 (JavaScript Closures E ...

最新文章

  1. atitit.复合变量,也就是类似$$a的变量的原理与实现 java c#.net php js
  2. verilator编译 更新文件的规则
  3. dataset.xsd的定义(vs2008)
  4. android dialog 隐藏状态栏_Flutter-最近搞了个项目-启动页Splash,Navigator.pop无法关闭Dialog...
  5. 使用SpringTest测试,默认情况事务是不会提交的
  6. HSImageSidebarView
  7. Reset Password Windows Server 2008 r2
  8. MVC架构下,使用NPOI读取.DOCX文档中表格的内容
  9. 使用pn532将全加密卡复制到手环上 NFC校园门禁卡模拟教程
  10. 输出100以内的素数
  11. 记录--前端路由 hash 与 history 差异
  12. php excel复选框,Element表格嵌入复选框以及单选框的方法介绍(代码示例)
  13. PS-给文字填充图片纹理
  14. https网站安全证书提示已过期怎么办?
  15. 解决win10下 git闪退的问题(或者使用git命令报错fatal: open /dev/null or dup failed)
  16. 人人网发布啵啵: 带语音滤镜的语音社交产品
  17. bmob php,文档-Bmob移动后端云服务平台
  18. Libvirt网络管理
  19. 计算点到直线/线段的距离
  20. [生而为人-思考] 读《网易一千零一夜》笔记

热门文章

  1. 第四范式完成超10亿元C轮融资,估值12亿美元
  2. 小米距告别破发还差2分钱
  3. Facebook悄悄参加星际AI大赛,然后输了 | 中国团队夺得第四
  4. react 使用webpack打包问题汇总
  5. 服务器端事件发送SSE
  6. 2012-10-29 → 2012-11-11 周总结:项目试运行(考验的时候到了),总算解决了WCF慢的问题了...
  7. 疲劳综合征的原因及解决办法
  8. 我为什么免费给ipad做了一个大广告?
  9. 每个电脑都会自己的SID号和GUID号,而且不会相同。。
  10. 学习日志---hbase学习(最大版本查询)