(Javascript) 猴子也明白 之 闭包超级入门 5 写一个闭包
比起理解什么是闭包,写一个闭包更简单
前回里,通过倒腾“函数中的函数”,竟然写出了一个闭包!
原来如此!
<script>
//Sample 5-1function outer(){
var x = 1; // outer里面定义一个变量return function (){ //这个函数就是传说中的「闭包」
alert(x); // "函数中的函数"里、参照外头函数outer里定义的变量。
};}
var f = outer();
f(); // 表示:1。
</script>
是否是闭包,需要满足以下条件:
- 在outer里定义了某变量
- 在outer里写一个函数(函数中的函数)
- 在函数中的函数里,参照刚才定义的变量
这么做有什么用?
“做出了闭包挺好,但有什么值得高兴的?”
--这是最大的疑问吧。
接下来,稍微改造一下上面的代码,执行一遍:
<script>
//Sample 5-2function outer(){
var x = 1;return function (){
x = x + 1;
};}
var f = outer();
f(); // 1
f(); // 2
f(); // 3</script>
!
!!
文章开头的问题被解决了:
问题:请写一个函数 f () ,随着调用次数,输出1,2,3,…
f(); // 1
f(); // 2
f(); // 3如何解决这一问题?
在上面的代码里面,第一回f ()被执行后的变量x的值(=2)并没有被清除掉,
在第二回f()被执行时,把2给alert出来后,又被加1,变成了3,
并且,变量x的值(=3)仍将继续保存下去。
使用闭包,就可以做出“可以保存状态的函数”。
也可以认为“闭包类似于对象”。
至此,100%理解闭包了。
接下来以jQuery为例,体验一下闭包在实际中的用处吧。
补充1 匿名函数不是必须的
上例Sample 5-2,就算不使用匿名函数,也可以有各种各样的写法。
(只是,一般闭包都与匿名函数一起出现,所以介绍了匿名函数。)
非匿名函数的闭包
// Sample 5-3
function outer(){
var x = 1;function inner(){
alert(x);
x = x + 1;
};return inner;
}var f = outer();
f(); // 1
f(); // 2
f(); // 3
PS:
匿名函数的另一个重要用途是区分命名空间,没熟悉匿名函数的童靴如果第一回看jQuery的源代码,
一定被如下的匿名函数的代码块震住了,然后感慨一下高手写的代码就是看不懂。(俺就是这样)
/*!
* jQuery JavaScript Library v1.7.2
* http://jquery.com/
*
* Copyright 2011, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2011, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Wed Mar 21 12:46:34 2012 -0700
*/(function( window, undefined ) {
// jQuery的源代码。中间省略M行
/*!
* Sizzle CSS Selector Engine
* Copyright 2011, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
* More information: http://sizzlejs.com/
*/(function(){
// Sizzle的源代码。中间省略N行
})
})( window );
其实以上的代码不是故作高深,而是为了自己的框架定义的变量不污染全局变量。
比如经典的变量$,在很多框架(如Prototype)里都定义了这个变量,为了不互相影响引入了匿名函数。
(详情参见jQuery.noConflict)
补充2 “闭包”(Closure)名字的由来
Closure再英文里有关闭的意思。
变量x,被关(closed)在outer函数的命名空间里,除了inner函数以外,谁都不能使用这个变量。(大概是这个意思吧)