js 闭包实质:
一个outer function里套inner function 而 inner function能够访问outer function定义的变量(类似于java内部类)。当然内部函数是对外不可见的。所以对内部函数的调用都要经过外部函数才行
典型的闭包
http://kb.cnblogs.com/page/110782/闭包经常用于创建含有隐藏数据的函数(但并不总是这样)。
var db = (function() {
// 创建一个隐藏的object, 这个object持有一些数据
// 从外部是不能访问这个object的
var data = {};
// 创建一个典型的闭包函数, 这个函数提供一些访问data的数据的方法。
return function(key, val) {
if (val === undefined) { return data[key] } // get
else { return data[key] = val } // set
}
// 我们可以调用这个匿名方法
// 返回这个内部函数,它是一个闭包
})();
db('x'); // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x'); // 返回 1
// 我们不可能访问data这个object本身
// 但是我们可以设置它的成员
js闭包在setInterval(setTimeout)中的应用:
http://www.cnblogs.com/fingerdancing/archive/2013/04/21/setIntervalClosure.html这两天在写一个页面自动刷新的jquery插件,写这个插件的过程遇到了一个问题,调用setInterval的时候,setInterval需要调用函数内部的参数变量。
首先,对于setInterval,https://developer.mozilla.org/en-US/docs/DOM/window.setInterval给出语法Syntax如下:
1 var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
2 var intervalID = window.setInterval(code, delay);
第一行我们可以看到,setInverval可以把函数func调用的参数作为setInverval的参数传递进来,但是下面这句说明却泼了我一盆冷水:
Note that passing additional parameters to the function in the first syntax does not work in Internet Explorer. If you want to enable this functionality on that browser you must use a compatibility code (see the Callback arguments paragraph).
也就是说,为setInterval调用的func传递参数的写法在IE下无效。IE下测试了一下,执行下面的代码:
1 var func = function(param) {
2 alert(param);
3 }
4 var foo = "success!";
5 setInterval(func, 3000, foo);
发现IE10下居然弹出了"success!",说明在IE10下还是有效的,但是IE7,8,9都华丽丽的弹出了"undefined"。在吐槽了官方说明的不准确之后,还得另寻它法。
那么你会这样想,为什么不直接这样写:setInterval('func(foo)', 3000),确实,如果foo是定义在window下的变量,那么肯定正确无误了。
setInterval使用内部函数
但是,如果foo是定义在函数内部的呢?比如下面这段代码:
1 var outerFunc = function() {
2 var foo = 'Success!';
3 var innerFunc = function(param) {
4 alert(param);
5 }
6 setInterval('innerFunc(foo)', 3000);
7 };
8 outerFunc();
执行了之后,console会无情的告诉你:Uncaught ReferenceError: foo is not defined
What's wrong?setInterval确确实实是写在outerFunc里面啊!不错,从outerFunc内部读取foo变量是妥妥的是能读出来的,但是你确定setInterval('innerFunc(foo)', 3000)中foo变量是在outerFunc内部读取的吗?
这里就涉及到setInterval两种语法的区别了,第一种setInterval(innerFunc, 3000),相当于做了下面三件事:
- var func = innerFunc;将innerFunc传递给func形参(其实传递的是一个闭包,后面再具体说明)
- 程序运行3000ms,这期间继续执行其他代码
- 执行func(),但是3000ms以后,func()的执行是在window对象下了,但是func()能取到outerFunc()内部的变量
也就是说,下面的这段代码可以弹出'success!'
1 var outerFunc = function() {
2 var foo = 'success';
3 var innerFunc = function() {
4 alert(foo);
5 };
6 setInterval(innerFunc, 3000);
7 };
8 outerFunc();
而第二种setInterval('innerFunc(foo)', 3000),只是相当于做了第一种的后面两件事
- 程序运行3000ms,这期间继续执行其他代码
- 执行innerFunc(foo),这时候innerFunc(foo)就是在window下执行了,连innerFunc都找不到,foo更不用说了
结合第一种不能给innerFunc传递参数但是却能读取outerFunc内部参数的特点,想到用闭包来解决这个问题:
具体做法是向setInterval(func, delay)传递一个闭包:
1 var outerFunc = function() {
2 var foo = 'success!';
3 var loop = function() {
4 innerFunc(foo);
5 };
6 var innerFunc = function(param) {
7 alert(param);
8 };
9 setInterval(loop, 3000);
10 };
11 outerFunc();
注意,这里传递的是loop()而不是loop。最后弹出'success!',表明setInterval中的闭包有效。
回顾闭包
A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).
Since a nested function is a closure, this means that a nested function can "inherit" the arguments and variables of its containing function. In other words, the inner function contains the scope of the outer function.
只看红字部分,首先闭包是函数(典型的情况),其次,闭包包含了外部函数的作用域链。只要建立了对闭包的引用(var func = loop;或者将loop作为实参传递给函数),就相当于变相读取了外部函数(outerFunc)的变量。
写到这里,感觉setInterval算是闭包的一个典型应用场景了吧(setTimeout同理)。
最后附上,写的自动刷新jquery插件的github地址:https://github.com/icefox0801/jquery_autoRefresh_js/blob/master/js/jquery.autoRefresh.js,其中包含闭包在setInterval中的应用,欢迎讨论!