js 之所以会有闭包,是因为 js 不同于其他规范的语言,js 允许一个函数中再嵌套子函数,正是因为这种允许函数嵌套,导致 js 出现了所谓闭包。
- function a(){
- function b(){
- };
- b();
- }
- a();
在 js 正常的函数嵌套中,父函数 a 调用时,嵌套的子函数 b 的结构,在内存中产生,然后子函数又接着调用了,子函数 b 就注销了,此时父函数 a 也就执行到尾,父函数 a 也会把自己函数体内调用时生成的数据从内存都注销。
- function a(){
- function b(){
- }
- return b;
- }
- var f=a();
这个例子中,父函数调用时,函数体内创建了子函数 b,但是子函数并没有立即调用,而是返回了函数指针,以备 "日后再调用",因为 "准备日后调用",此时父函数 a 执行完了,就不敢注销自己的作用域中的数据了,因为一旦注销了,就把创建的子函数 b 的结构都从内存中注销,子函数连结构都没有了,日后还怎么调用?同时如果注销了,即便子函数能够日后再调用,但它在调用时沿着函数作用域链往上访问数据,也没有数据可以访问了。
正因此,子函数要 "日后调用",导致父函数不敢注销自己的作用域数据,那么这个子函数就是 "闭包函数"。
闭包函数在形式上有很多种,并不是只有 return 返回函数这一种。
在这个例子中,父函数 v() 体内定义了好几种子函数,这些子函数有的是异步事件的回调函数,会进入浏览器的事件循环池,等主线程工作结束后日后再调用这些回调函数,这些子函数,都导致父函数调用完了,不敢注销自己的作用域,因此这些子函数都是闭包函数。
js 并不是为了创造闭包而创造,完全只是因为 js 允许函数嵌套,还能 return 返回子函数,以及 js 特有的事件循环机制,导致这些子函数不是立即调用,让父函数不敢注销自己作用域中的数据,才会产生所谓闭包。
也正因为这个闭包这个特性,闭包函数可以让父函数的数据一直驻留在内存中保存,从而这也是后来 js 模块化的基础。
来源: http://www.tuicool.com/articles/7nAfiev