【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

时间: 2024-11-07 06:28:30

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

Javascript闭包[转载]

本文转载:阮一峰javascript闭包closure 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. 1 var n=999; 2 function f1(){ 3 alert(n); 4 } 5 f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. 1 function f1(){ 2 var n=999; 3 }

javascript闭包详解(内容为转载的,觉得不错就分享一下)

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

我从来不理解JavaScript闭包,直到有人这样向我解释它...

正如标题所述,JavaScript闭包对我来说一直有点神秘,看过很多闭包的文章,在工作使用过闭包,有时甚至在项目中使用闭包,但我确实是这是在使用闭包的知识. 最近看国外的一些文章,终于,有人用于一种让我明白方式对闭包进行了解释,我将在本文中尝试使用这种方法来解释闭包. 准备 在理解闭包之前,有个重要的概念需要先了解一下,就是 js 执行上下文. 这篇文章是执行上下文 很不错的入门教程,文章中提到: 当代码在JavaScript中运行时,执行代码的环境非常重要,并将概括为以下几点: 全局代码--第

深入理解JavaScript系列(结局篇)(转载)

深入理解JavaScript系列(结局篇) 介绍 最近几个月忙得实在是不可开交,终于把<深入理解JavaScript系列>的最后两篇“补全”了,所谓的全是不准确的,因为很多内容都没有写呢,比如高性能.Ajax安全.DOM详解.JavaScript架构等等.但因为经历所限,加上大叔希望接下来写点其它东西,所以此篇文字就暂且当前完结篇的总结吧,以后有时间的话,可以继续加上一些未涉及的专题内容. 网络文章来源 本系列文章参考了大量的互联网网站,在此向各位网站拥有者.博主.提到的以及未提到的作者们说一

最简明的JavaScript闭包解释

最简明的JavaScript闭包解释 JavaScript是这几年最火的编程语言之一,从前端到服务器端,再到脚本,好像没有一个地方没有JavaScript的身影.这个世界上任何的一种事物的存在必然有其合理性,不要以为别人都是小人得志,学习众家的长处才能开阔视野,青出于蓝. JavaScript的闭包是其相对于好多传统语言不太容易理解的地方,其实并不是它有多难,因为我们好多朋友都是有其他语言背景的,比如C/C++或者Java,这样往往可能会有些先入为主的思维,导致不容易一下子转变过来,其实稍微习惯

转载: javascript 闭包

转载自阮一峰 : http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html 学习Javascript闭包(Closure) 作者: 阮一峰 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于Javascript初学者应该是很有用的. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无

解密JavaScript闭包

title: 解密JavaScript闭包 date: 2017-07-31 10:00:00 tags: [JavaScript, 翻译] 译者按: 从最简单的计数器开始,按照需求对代码一步步优化,我们可以领会闭包的神奇之处. 原文: Closures are not magic 译者: Fundebug 为了保证可读性,本文采用意译而非直译.另外,本文版权归原作者所有,翻译仅用于学习. 对于JavaScript新手来说,闭包(Closures)是一个很神奇的东西.这篇博客将通过一个非常浅显的

通过示例学习JavaScript闭包

译者按: 在上一篇博客,我们通过实现一个计数器,了解了如何使用闭包(Closure)**,这篇博客将提供一些代码示例,帮助大家理解闭包. 原文: JavaScript Closures for Dummies 译者: Fundebug 为了保证可读性,本文采用意译而非直译.另外,本文版权归原作者所有,翻译仅用于学习. 闭包并不神奇 其实,只要你领会了闭包的关键概念,一切就非常简单了.作为JavaScript开发者,你应该可以理解以下代码: Example 1 function sayHello(

傻瓜学习JavaScript闭包(译)

在<高级程序设计>中,对于闭包一直没有很好的解释,在stackoverflow上翻出了一篇很老的<JavaScript closure for dummies>(2016)~ 出处:http://stackoverflow.com/questions/111102/how-do-javascript-closures-work 闭包不是魔法 本文旨在用JavaScript代码让程序员理解闭包,函数式编程的程序员或者导师请绕行. 只要理解了闭包的核心理念,闭包并不难学.但是通过学习一