首页 > 代码库 > JavaScript闭包模型
JavaScript闭包模型
JavaScript闭包模型
----- [原创翻译]2016-09-01 09:32:22
《 一》 闭包并不神秘
本文利用JavaScript代码来阐述闭包,目的是为了使普通开发者能很好的理解闭包,并不面向专家或函数式编程开发者。
一旦领悟了闭包的核心思想,它就不再难于理解;然而,只看一些理论上的文档或是以理论为中心的文档只会让你南辕北辙。
本文适用于那些在主流编程语言中有一定编程经历的开发者们,且能看懂如下的JavaScript函数:
1 function sayHello(name) {2 var text = ‘Hello ‘ + name;3 var say = function() { console.log(text); }4 say();5 }
《二》 闭包实例
两句话总结:
- 闭包是支持 头等函数(first-class functions)的一种函数;它是一个能在其作用域类引用变量(变量先被声明),赋值给另外一个变量,作为一个参数传递给其他函数,或是作为一个函数的结果返回。又或者--
- 闭包是函数开始执行时分配出来的一个栈帧,且当函数返回后不会被释放(类似于‘栈帧’是在堆上被分配而不是在栈上被分配!)。
下面的代码返回给另一个函数一个引用。
1 function sayHello2(name) {2 var text = ‘Hello ‘ + name; // Local variable3 var say = function() { console.log(text); }4 return say;5 }6 var say2 = sayHello2(‘Bob‘);7 say2(); // logs "Hello Bob"
运行结果:(--PS:译者添加--)
大部分的开发者都够能理解上面的代码中一个函数的引用是如何返回给一个变量(say2)。如果你这还不能看明白的话,那么你需要去学习基础的知识而不应该是闭包了。一个C 语言开发者会理解为一个函数返回了一个指针给另外一个函数,变量say 与say2分别是两个函数的指针。
而C语言中指针指向一个函数与JavaScript里一个函数的引用有一个很关键的区别。那就是,在JavaScript中,你可以理解为一个函数引用变量是一个指针指向一个函数,同时又是一个隐式的指针指向闭包。
上面的代码中存在一个闭包,因为匿名函数 function() {console.log(text);}在其他函数里面有被定义了,实例中在sayHeelo2()函数中定义的。在JavaScript中,如果你在另一个函数中使用function关键字,那么你就正在创建一个闭包。
在C与其他类似的编程言语里,当一个函数返回后,所有的局部变量将不会再可利用,因为栈帧已经被销毁。
在JavaScript中,如果你在一个函数中声明另一个函数,那么局部变量在从你调用的函数返回后依然可以使用。正像上面演示的那样,因为我们从sayHello2()返回之后再调用的say2()注意到我们调用的代码里面有text这个变量,而这个变量是sayHello2()函数里的一个局部变量。
仔细观察say2.toString()的输出,我们不难发现这段代码引用了text变量。匿名函数能够引用包含值为‘Hello Bob‘的text,原因就在于sayHello2()的局部变量被保存在闭包中。
神秘就在于JavaScript里的函数引用也是对函数中创建的闭包的一个隐式引用---类似于委托是加在某一个对象上面的隐式引用的一个方法指针。
《三》 更多实例
出于某些原因,当你只看相关文档时,发现闭包好像确实难于理解,但是当你结合一些实例就能够了解到它们到底是如何工作的(可能会花费我们一些时间)。建议在实践中认真学习直到你理解它们是如何工作的。如果你在没有完全理解闭包是如何工作的就使用她们,估计你可能搞出很多非常糟糕的bug。
实例1:
本例演示了局部变量不被复制—它们被保存在引用中。这就好像当存在着一个函数的时候在内存中存一个相应的栈帧。
实例1运行结果:(--PS:译者添加--)
实例2:
三个全局函数都有对同一个闭包的引用,因为它们都单独被定义来调用setupSomeGlobals().
实例2运行结果:(--PS:译者添加--)
(翻译自stackoverflow社区;原文信息:作者:Morris 发布时间:2006-02-21)
原文链接
JavaScript闭包模型