私人博客文章地址: 今天在看《Professional Node.js》的时候提到了闭包,说闭包的机制可以帮助事件驱动的编程模式( event-driven programming)的实现。
为了弄清楚闭包的概念翻看了各种各样的文档。下面总结一下个人的理解,此文章不一定权威,但也不会瞎说的,囧~ ##什么是闭包,先别急
闭包的概念被各种人定义的神乎其神,看了之后不懂是常态。其实理解闭包的概念还是应该从需求说起,这样比较好理解。
首先,我们必须知道,闭包并不是js得专利,这一概念也不是从js中创造出来的,今天的大部分高级语言(Python、Ruby、Lua等)都支持闭包这一特性。那么闭包究竟是什么,别急,让我慢慢道来,在这里我可以先说明一点:闭包是为了给现今的高级语言增加灵活性所催生出的产物。虽然我只是感觉,但我觉得闭包这个东西的出现有点“迫不得已”的意味,为什么这么说呢,因为在js这类脚本语言当中增加了很多传统语言没有的东西,比如作用域链、把函数作为“第一类对象”(first-class object)等特性,而为了维持这些特性,就必须引入闭包机制。 ##传统的函数调用方式
我们先看看传统的函数是怎么工作的。
函数内部的代码与外界的联系仅限于传参机制和返回值机制。说的更底层一些,每个函数在调用时在内存中用独立的栈储存,调用完成之后,回收所用栈的内存。这过程中的输入输出就是传参和return。而函数内部所用到的变量全部是局部变量,在函数直接完成之后就释放了,和整个程序没有太大关系。 ##javascript的高级特性
而在js中,有了两个明显的特性,改变了上面所说的比较简单的函数执行方式。
第一个是作用域链的概念。传统的函数内部的作用域只有函数内部本身和传入的参数。而在js中,作用域向上扩展。内部函数可以看到并利用其母函数中的变量和全局变量。并且可以直接在函数内部使用它们。这就造成了子函数与母函数的耦合特性。当你调用一个子函数时,其母函数中所用到的部分也必须被调用。而这个被调用的整体(并非只有子函数本身)就被称作一个闭包。
第二个是把函数作为“第一类对象”(first-class object)。函数在js中可以被赋予给一个变量,可以被当做一个参数传给另一个函数,还可以作为一个函数的返回值。这都得益于其函数在语言中作为“第一类对象”。这就使函数的嵌套成为常态。函数可以被当做变量任意传递、返回。这就使函数的必须明确自己的作用域。当被变量引用到其他位置是,还是要绑定它自己原有的作用域。而这个被作用域捆绑到一起的代码集合就是闭包。 ##举个栗子
通过上面的两点,也许你对闭包已经有了一定了解,其实想更深入的弄清楚闭包,重要的是弄清楚函数运行的机制。
好吧,下面我们举个例子:
当一个子函数引用一个母函数中的变量,且又将这个子函数作为母函数的返回值返回(有点绕,都读两边,囧~)。具体参照下面代码。
function f1() var n=999; function f2(){ alert(n); } return f2;}var result=f1();result(); // 999
当你最后调用 result()时,其实就产生了闭包。result引用的其实是f2;因为f2作为了f1的返回值。而f2中有调用了f1中的n,所以,在返回时,n也要连带的被返回出来。其实用起来合情合理。没神马异常的地方。 ##闭包与node.js
node.js用的是事件驱动型编程或者叫一步编程。所有的任务由事件触发,这就要在事件函数中大量遇到回调函数(call back),而回到函数基本上都会触发闭包机制,也就是调用函数外部的变量。而有了闭包机制,这些事情全部不需要编程者操心,而是由语言本身帮你完成。最后引用《Professional Node.js》中的话
This shows that by using the closure pattern, you can have the best of both worlds: You can do event-driven programming without having to maintain the state by passing it around to functions. A JavaScript closure keeps the state for you.
好啦,今天就写到这!明天讲讲node.js的事件驱动机制(event-driven)。