【javascript闭包】转载一篇不错的解释,也有几个大牛的链接
初学闭包时一直以为很简单。但伴随对一个问题深入学习后,才算真正理解了闭包,同时也发现连<<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
【javascript闭包】转载一篇不错的解释,也有几个大牛的链接的更多相关文章
- javascript 闭包 转载
http://www.jb51.net/article/24101.htm var name = "the window"; var object = { name:"m ...
- 我从来不理解JavaScript闭包,直到有人这样向我解释它...
摘要: 理解JS闭包. 原文:我从来不理解JavaScript闭包,直到有人这样向我解释它... 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 正如标题所述,JavaScript闭包 ...
- 我从来不理解 JavaScript 闭包,直到有人这样向我解释它...
正如标题所述,JavaScript 闭包对我来说一直有点神秘,看过很多闭包的文章,在工作使用过闭包,有时甚至在项目中使用闭包,但我确实是这是在使用闭包的知识. 最近看国外的一些文章,终于,有人用于一种 ...
- JavaScript闭包,只学这篇就够了
# 闭包不是魔法 这篇文章使用一些简单的代码例子来解释JavaScript闭包的概念,即使新手也可以轻松参透闭包的含义. 其实只要理解了核心概念,闭包并不是那么的难于理解.但是,网上充斥了太多学术性的 ...
- JavaScript闭包只学这篇就够了
闭包不是魔法 这篇文章使用一些简单的代码例子来解释JavaScript闭包的概念,即使新手也可以轻松参透闭包的含义. 其实只要理解了核心概念,闭包并不是那么的难于理解.但是,网上充斥了太多学术性的文章 ...
- javascript深入理解js闭包(转载)
此篇文章来源于http://www.jb51.net/article/24101.htm 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全 ...
- javascript闭包—围观大神如何解释闭包
闭包的概念已经出来很长时间了,网上资源一大把,本着拿来主意的方法来看看. 这一篇文章 学习Javascript闭包(Closure) 是大神阮一峰的博文,作者循序渐进,讲的很透彻.下面一一剖析. 1. ...
- 最简明的JavaScript闭包解释
最简明的JavaScript闭包解释 JavaScript是这几年最火的编程语言之一,从前端到服务器端,再到脚本,好像没有一个地方没有JavaScript的身影.这个世界上任何的一种事物的存在必然有其 ...
- 上一篇括号配对让人联想起catalan数,顺便转载一篇归纳的还不错的文章
转载请注明来自souldak,微博:@evagle 怎么样才是合法的组合? 只要每一时刻保证左括号的数目>=右括号的数目即可. 直接递归就行,每次递归加一个括号,左括号只要还有就能加,右括号要保 ...
随机推荐
- 饿汉单例模式 and 懒汉单例模式
饿汉单例模式:主要就是利用static关键字,在类加载的时候生成实例,调用效率高 但是如果一直没有调用getInstance方法的话,就会造成资源浪费 具体实现如下: class Single{ pr ...
- Android面向切面编程(AOP)(转)
转自:https://www.jianshu.com/p/aa1112dbebc7 一.简述 1.AOP的概念 如果你用java做过后台开发,那么你一定知道AOP这个概念.如果不知道也无妨,套用百度百 ...
- 转帖 Java生成和操作Excel文件
JAVA EXCEL API:是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容.创建新的Excel文件.更新已经存在的Excel文件.使用该API非Windows操作系统也可以通过 ...
- word--->pdf资料转载..
https://blog.csdn.net/dsn727455218/article/details/80667927
- Oracle 19C的下载和安装部署
1.官网下载zip包. 2.解压到/usr/local/oracle 目录. 3.创建用户和用户组 /usr/sbin/useradd -u oracle //用户组oracle /usr/sbin/ ...
- JavaSE---环境配置
1.概述 1.1 PATH环境变量 a,Java程序 编译.运行时 需要用到java.javac命令,虽然计算机中已经安装了JDK,但是计算机不知道去哪里找这个命令: b,计算机如何查找命令呢 ...
- java模式-----单例模式
什么是单例设计模式? 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 类结构 ...
- linux下oracle数据库服务和监听的启动停止
oracle数据库是重量级的,其管理非常复杂,将其在linux平台上的启动和关闭步骤整理一下. 安装完毕oracle以后,需要创建oracle系统用户,并在/home/oracle下面的.bash_p ...
- uORBMain.cpp学习
uorb_main int uorb_main(int argc, char *argv[]) { if (argc < 2) { usage(); ...
- Java中如何修改Jar中的内容
一.摘要 好长时间没写blog了,之前换了一家公司.表示工作更有战斗力了,可惜就是没时间写文章了.在这段时间其实是遇到很多问题的,只是都是记录下来,并没有花时间去研究解决.但是这周遇到这个问题没办法让 ...