Skip to content

Latest commit

 

History

History
77 lines (55 loc) · 5.63 KB

jsclosure.md

File metadata and controls

77 lines (55 loc) · 5.63 KB

##JavaScript Closures for Dummies ##

link: http://stackoverflow.com/questions/111102/how-do-javascript-closures-work

维基百科,自由的百科全书 在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

闭包的概念出现于60年代,最早实现闭包的程序语言是Scheme。之后,闭包被广泛使用于函数式编程语言如ML语言和LISP。很多命令式程序语言也开始支持闭包。

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的 函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。其中所引用的变量称作上值(upvalue)。

闭包一词经常和匿名函数混淆。这可能是因为两者经常同时使用,但是它们是不同的概念。

闭包不是万能

这篇文章是为让程序员能理解JS闭包。

闭包的核心并不难理解。然而,大多数的学术文档和原始信息却晦涩难懂。

这篇文章写给一些知道主流程序语言并能理解以下js代码的程序员:

function sayHello(name) {
    var text = 'Hello ' + name;
    var say = function() { console.log(text); }
    say();
}

一个闭包例子

两句话总结闭包

  • 闭包是头等函数的一种执行方式;这个表达式可以在一定作用域内引用变量、赋值变量、作为别的函数的参数、返回一个函数
  • 闭包被分配了栈帧,当函数开始执行,并在函数返回之后不会释放。

下面的代码返回一个函数的引用:

function sayHello2(name) {
    var text = 'Hello ' + name; // Local variable
    var say = function() { console.log(text); }
    return say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello Bob"

大部分js程序员都能理解然后把一个函数的引用付给一个变量。如果你还不理解,那你在学习闭包前必须先了解它。C程序员会把它理解为返回一个函数的指针,而变量say和say2都指向了函数。

对于c指针和js引用之间很大的区别是在js中你可以把一个引用函数的变量当成同时拥有指针指向函数和一个隐藏指针指向闭包。

上面的代码是一个闭包,因为匿名函数 function() {console.log(text);} 被声明在另一个函数内,就是sayHello2()。在js中,如果你在一个函数内创建了另一个函数,你就是创建了闭包。

在c和其他大多数的语言中,返回一个方法,所有本地变量都将无法访问,因为他们的栈帧被销毁了。

而在js中,如果你在一个函数中声明了另一个函数,那这个函数中的本地变量可以保持访问即使函数已经返回值(return)。上述论证中,sayHello2()返回say2()是闭包,并且,我们在say2()引用的变量text是sayHello2的本地变量。

function() { console.log(text); } // Output of say2.toString();

如果我们输出say2.toString(),我们可以看到能引用到text。匿名函数可以引用test,因为sayHello2中的本地变量被保持在了闭包中。

神奇的是,js让一个函数引用到一个已经创建了的秘密闭包。类似委托是如何让一个方法的指针秘密的引用一个对象。

最后

  • 无论何时你调用了一个函数内的另一个函数,那就是在使用闭包。
  • 无论何时你在一个函数内使用eval(),就是在使用闭包,你的eval可以引用函数的本地变量,而在eval内你可以通过使用eval('var foo = ...')创造新的本地变量
  • 当你在一个函数内使用new Function(...) (构造函数),这并没有创造闭包。(新的方法不能引用父级的本地变量)
  • js中的闭包就好像保持了一个本地变量的拷贝,就算函数调用完毕也将存在。
  • 可能对闭包最好的理解是永远为函数创建一个入口,并且本地变量会被加到闭包中。
  • 一组新的局部变量保持每一个封闭的函数被调用时(假定该函数包含它里面的函数声明,以及里面函数的引用要么返回或外部参考保持它以某种方式)。
  • 两种功能可能看起来像它们具有相同的源文本,但因为他们的'隐藏'封闭完全不同的行为。我不认为JavaScript代码实际上可以找出一个函数的引用有一个封闭与否。
  • 如果你正在尝试做的任何动态修改源代码(例如:myFunction的=功能(myFunction.toString()代替(/你好/,“霍拉'));),如果myFunction是闭包将无法正常工作(当然,你永远别想做在运行时的源代码字符串替换的,但是......)。
  • 它可以在函数的声明得到函数中函数声明 - 你可以在多个级别得到关闭。
  • 我认为,通常是关闭是两个与被捕获的变量沿功能项。请注意,我不使用这种定义在这篇文章中!
  • 我怀疑,在JavaScript中关闭那些通常在功能性语言中有所不同。

Links: Douglas Crockford's simulated private attributes and private methods for an object, using closures. A great explanation of how closures can cause memory leaks in IE if you are not careful.