按照惯例,先看下官方是如何定义的
Closures are functions that refer to independent (free) variables.
In other words, the function defined in the closure 'remembers' the environment in which it was created in.
第一句:闭包是函数,什么样的函数?涉及到独立变量的函数。什么叫“独立变量”?我也不明白,一会边写边说。
第二句:换言之,这个函数是在闭包的‘记忆’环境定义。“记忆环境”是什么东东?还是不明白。
好吧,以我苦逼的英语水平,就只能这样理解了。但这说了什么?我不明白,一点都不明白。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures 链接在这里,英语好的少年可以去看看。
再看另一个定义
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression)
http://jibbering.com/faq/notes/closures/
闭包是一个表达式(通常是一个函数),什么样的表达式?拥用自由变量和一个绑定这些变量的环境的表达式。
这个定义相对要明白一些,但还是不太具体。再看看wiki
In programming languages, a closure (also lexical closure or function closure) is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables or upvalues) of that function.A closure—unlike a plain function pointer-allows a function to access those non-local variables even when invoked outside its immediate lexical scope.
http://en.wikipedia.org/wiki/Closure_(computer_programming)
好吧,又是乱七八糟的一大堆,但是最后一句很关键:闭包不像一般函数,它允许一个函数访问这些变量,即使这些引用超出了变量的作用哉。
诸位不要觉得看定义是很烦人,是没有必要的。在我看来这是非常非常重要的东西。因为大多知识点,在定义上面都写得很清楚。不过closures算一个例外吧,因为它本来就很难说清楚......
既然国外文献定义得不太明白,就看看国内的先辈们有没有好的定义,摘录如下:
1.闭包就是能够读取其他函数内部变量的函数。
2.闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
3.闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。
4. 闭包是定义在另一个函数中的匿名函数。(javascript详解第二版 ——Ellie Quigley Page 124)
对于第3条,是来自百度百科,看了之后我只能说:壮哉我大百度!还有比这更详尽的定义么?有发现的请发给我!
这里对自由变量有个解释:未绑定到特定对象的变量。
大部份程序员由于逼格原因,是鄙视百度的,动辙google,跳辙wiki。殊不知知识莫问出处,好用就行。
这里多说两句,除了一些新的知识,国内论坛基本都有非常详尽的资料,如果你没有达到国内的资料已经不有满足你的程度,就不要到处找英文资料,因为母语资料理解起来,肯定比英文快得多。
嗯,直白点说就是:在程序这一块,英语是用来用的,而不是用来show的。
======================================================================
所以,我们总结一下什么是闭包:
什么时候需要用到闭包:
1.需要在一个函数外部,访问函数内部的变量的时候(也就是说在函数运行完之后,你想要把变量保存下来,待需要的时候调用。而不是通过垃圾回收机制消除(garbage collection))。
2.保护变量安全。一个函数的内部变量,只能内部函数引用。
如何定义闭包:在一个函数内部,定义一个函数,并返回一个函数的引用。
======================================================================
如何在外部引用一个函数内部的变量?
//===============================
function a(){
var i = 1;
}
alert(i); //undifined
//===============================
为什么这样?因为一个变量的作用域只在一个函数本身,这是javascript最基本的入门的概念,想来不用多说。
//===============================
function a(){
var i=0;
function b(){
alert(++i);
}
return b;
}
var c = a();
c(); //1;
//===============================
这个例子来自于百度百科,有两个关键点
1. b是定义在a的内部
2. a的运行结果是 return b。此时b就一直保存在内存当中,直到你手动删除为止。
3. b引用了a的变量(这一点极其重要)。
所以,c = a();其实调用的就是b,由于b是在a的内部,所以就可以访问i(这是javascript的链接作用域(chain scope),内部函数可以访问外部函数的变量)。
这样,就达到了在a的外部,调用a中的变量。
再有,a中定义的函数是b,而不是一个匿名函数,但是这样是可行的。所以,上面第4条的定义就是错的,闭包并不一定是一个匿名函数。
这一个例子,基本就已经说完了闭包了。但是看的人可能还是没有一个明确的概念,那么就继续看几个例子。
//===============================
function a(){
var i = 1;
function b(){
alert(i);
}
i++;
return b;
}
var f = a();
f(); // 2
为什么呢是2呢?
return b是在a的最后执行,所以,在ruturn b的时候,已经将a中代码全部执行了,所以 i=2;若在i++前返回b。f()的结果就是1。这就可以推出:也可以把 var i = 1;写在function b的后面。只要写在return之前即可。
function a(){
var i = 1;
function b(){alert(i)}
return b;
i++;
}
//===============================
//===============================
function a(){
var i = 1;
b = function(){alert(i)}
c = function(){i++}
d = function(j){i = j}
}
a(); //运行一次a,为b\c\d赋值。
b(); // 1
c(); // i++
b(); // 2
d(3); // i = 3
b(); //3
此处应有三点需要说明:
1. 在函数内部定义变量一定要用var,否则定义的就是一个全局变量。在这里b c d皆没有用var,所以就可以在外部直接调用这三个全局变量
2. a需要运行一次,才会给bcd赋值。否则会报错 b c d未定义
3. b c d 都在a内,所以都可以调用变量i.
//===============================
循环中的闭包
//===============================
function closureInLoop(Ar){
var result = [];
for(var i=0;i<Ar.length;i++){
var item = 'item' + Ar[i];
result.push(function(){alert(item + ' ' + Ar[i])});
}
return result;
}
function test(){
var fnList = closureInLoop([1,2,3]);
alert(fnList);
for(var j=0;j<fnList.length;j++){
fnList[j]();
}
}
test(); // item3 undifined(3次);
我原以为,会依然出现item 1,item 2,item 3。结果却不同,这是什么原因?
先把fnList输出来看看[fnction(){alert(item + ' ' + Ar[i])},function(){alert(item + ' ' + Ar[i])},function(){alert(item + ' ' + Ar[i])},]
三个一模一样的function,都是调用的Ar[i]。此时i是多少呢?看下前面的closureInLoop的for循环。
传入的参数是[1,2,3],所以closureInLoop中的Ar.length就是3。所以for执行完的时候:
i=3;
item = 'item' + Ar[2];也就是item3;
由于return result了。所以此时resulte里面的function就形成了闭包。
三个function都引用了i和item。此时i=3,item = item3;
所以都是function(){item + ' ' + Ar[3]}
但是Ar传入的是[1,2,3],Ar.length = 3 没错。
但是Ar[0] = 1;Ar[1] = 2; Ar[2] = 3....都没错。
但是骚年们,Ar[3] = undifined;
alert(item + ' ' + Ar[3]) = item3 undifined。
Over,这个太麻烦,我想也没几个人这样写吧。不过这个例子非常经典,可以仔细看看。
例外一种循环里的闭包
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i);
},1000);
}
这样并不能依次输出i,而是输出10次10。
//===================================
每次都创建一个新的闭包
//===================================
function createClosure(number,reference){
var num = number,
ref = reference,
anArray = [1,2,3];
return function(x){
num += x;
anArray.push(num);
alert(num + ' ' + anArray.toString() + ' ' + ref);
}
}
closure_1 = createClosure(20,'ref_1');
closure_1(10); //30 [1,2,3,30] ref_1
closure_2 = createClosure(100,'ref_2');
closure_2(-10); //90 [1,2,3,90] ref_2
说好的闭包呢,为什么没有继续用closure_1的nunber和reference?
因为我们每建立一个新的闭包,都重新将number和reference的通过参数改变。
//===============================
参考资料
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
http://jibbering.com/faq/notes/closures/
http://en.wikipedia.org/wiki/Closure_(computer_programming)
http://baike.baidu.com/view/648413.htm
http://coolshell.cn/articles/6731.html
http://bonsaiden.github.io/JavaScript-Garden/zh/
文章转载处:
http://tieba.baidu.com/p/2966931266#
分享到:
相关推荐
Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态...本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点 ECMAScript语言规范来使读者可以更深入的理解闭包。
JavaScript 闭包研究及典型应用 JavaScript 闭包是一种强大的技术,能够在各种场景中发挥重要作用。本文将介绍 JavaScript 闭包的定义、使用场景和典型应用。 闭包函数的定义和使用场景 在 JavaScript 语言中,...
基于JavaScript闭包的Web图片浏览控件的实现 本文主要讲解了基于JavaScript闭包原理的Web图片浏览控件的实现,包括JavaScript闭包概念、闭包应用场景、Web图片浏览控件的设计思路和实现方法。 1. JavaScript闭包...
闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
资源名称:javascript闭包详解 中文word版 内容简介: Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态语言C/C 的程序员来说是一个新的...
### JavaScript闭包完整解释 #### 一、闭包的基本概念 **闭包**是一个非常重要的JavaScript概念,它指的是一个函数能够记住并访问其外部作用域中的变量的能力,即使该函数在其外部作用域之外被调用也是如此。具体...
在深入讨论JavaScript闭包之前,首先需要了解JavaScript的变量作用域。在JavaScript中,变量的作用域分为两种:全局变量和局部变量。全局变量是在函数外部定义的变量,可以在JavaScript程序的任何地方被访问。局部...
标题《JavaScript闭包的理解》涉及的知识点主要围绕JavaScript编程中的一个重要概念——闭包。闭包是一个高级且复杂的话题,它是JavaScript语言的核心特性之一,同时也是一大难点。要想熟练运用JavaScript,掌握闭包...
JavaScript 闭包是一种高级编程概念,它在JavaScript中扮演着至关重要的角色,特别是在函数式编程和模块化设计中。闭包本质上是函数和其能够访问...通过学习这些实例,你将能够更好地掌握JavaScript闭包这一核心概念。
### JavaScript闭包技术详解 #### 一、闭包的基本概念 **闭包**是JavaScript中一个重要的概念,它涉及到函数的执行环境、作用域链等关键要素。简单来说,闭包是一个函数及其相关的引用环境的组合。具体而言,当一...
详解JavaScript闭包问题 闭包是纯函数式编程语言的传统特性之一。通过将闭包视为核心语言构件的组成部分,JavaScript语言展示了其与函数式编程语言的紧密联系。由于能够简化复杂的操作,闭包在主流JavaScript库...
### JavaScript闭包高级教程 #### 简介 在JavaScript编程中,“闭包”是一个非常重要的概念,尤其对于希望深入理解和高效使用JavaScript的开发者来说。简单地说,闭包是一种能够记住并访问其创建时周围环境的函数...
JavaScript 闭包是一种强大的特性,它允许函数访问和操作其外部作用域中的变量,即使在外部函数执行完毕后,这些变量仍然保持活动状态。在高级使用中,闭包可以用于实现模块化、数据封装、方法扩展和重载、以及创建...
【JavaScript 闭包详解】 闭包是JavaScript编程中一个核心且关键的概念,尤其对于初学者而言,理解起来可能有些挑战。闭包本质上是一种特殊的作用域,它可以捕获并存储其外部函数作用域内的变量,即使外部函数已经...
### JavaScript闭包的理解 #### 一、闭包的定义与特点 闭包是JavaScript中一个非常重要的概念,它指的是一个函数能够访问并操作其外部作用域中的变量的能力。这一特性使得JavaScript具有了一些其他语言不具备的...
### JavaScript闭包详解 #### 引言 JavaScript作为一种动态、弱类型的编程语言,在Web开发领域占据了举足轻重的地位。其中,“闭包”是JS语言中一个非常重要的概念,它不仅能够帮助开发者实现某些特殊的功能,如...
理解并掌握JavaScript闭包是成为专业前端开发者的关键一步。在实际开发中,合理利用闭包可以提高代码的复用性和可维护性,同时也能避免一些常见的编程陷阱。通过深入学习和实践,可以更好地运用闭包这一强大的工具来...