阮一峰有一篇关于javascript 闭包的科普文章:
学习Javascript闭包(Closure)
感觉讲的挺好的,考虑到之前被朴灵喷的很惨,所以开始怀疑博文中的讲解是否正确。
博文部分观点:
1. 我的理解是,闭包就是能够读取其他函数内部变量的函数。
2.由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
3.闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!不使用 var 等於沒有聲明變量,而是相當於訪問了 window 的屬性。
<code class="language-js"><span class="nb">window</span><span class="p">.</span><span class="nx">b</span> <span class="o">=</span> <span class="s2">"hi"</span><span class="p">;</span> <span class="nx">b</span><span class="p">;</span> <span class="c1">// "hi"</span> <span class="k">delete</span> <span class="nx">b</span><span class="p">;</span> <span class="c1">// true</span> <span class="nx">b</span><span class="p">;</span> <span class="c1">// ReferenceError: b is not defined</span> <span class="p">(</span><span class="kd">function</span><span class="p">(){</span><span class="nx">c</span> <span class="o">=</span> <span class="s2">"hi"</span><span class="p">}());</span> <span class="nx">c</span><span class="p">;</span> <span class="c1">// "hi"</span> <span class="k">delete</span> <span class="nx">c</span><span class="p">;</span> <span class="c1">// true</span> <span class="nx">c</span><span class="p">;</span> <span class="c1">// ReferenceError: c is not defined</span> <span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="s2">"hi"</span><span class="p">;</span> <span class="nx">a</span><span class="p">;</span> <span class="c1">// "hi"</span> <span class="k">delete</span> <span class="nx">a</span><span class="p">;</span> <span class="c1">// false</span> <span class="nx">a</span><span class="p">;</span> <span class="c1">// "hi"</span> </code>
<code class="language-text">var a = function () { var test = {}; setTimeout(function () { console.log(test); }, 1000); } </code>
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
搞的好像其他面向对象的语言不能似的。另一方面,在函数外部自然无法读取函数内的局部变量。
根本没有提到关键,为什么不能读取内部变量?函数在执行完后会销毁其内部环境这个就没提及。如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。
<code class="language-text">var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); </code>
闭包并不是什么新奇的概念,它早在高级语言开始发展的年代就产生了。闭包(Closure)是词法闭包(Lexical Closure)的简称。对闭包的具体定义有很多种说法,这些说法大体可以分为两类:
这两种定义在某种意义上是对立的,一个认为闭包是函数,另一个认为闭包是函数和引用环境组成的整体。虽然有些咬文嚼字,但可以肯定第二种说法更确切。闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。那么为什么要把引用环境与函数组合起来呢?这主要是因为在支持嵌套作用域的语言中,有时不能简单直接地确定函数的引用环境。这样的语言一般具有这样的特性: