这涉及到var作为变量声明的关键词时所出现的一些问题。
比如,var 的 变量提升
以及 函数级作用域
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。 另一方面,在函数外部自然无法读取函数内的局部变量。
需要注意的是,如果在函数内部声明变量时没有使用var关键词,实际上声明的是一个全局变量,如下:
function f1(){
n = 999;
}
//console.log(n); // ReferenceError: n is not defined
f1();
console.log(n); // 999
这里为什么第一处会报错呢?关于这个问题下面有比较基础的解释:
JS的解析过程分为两个阶段:预编译期(预处理)与执行期。
正因为从外部访问在函数内部进行声明的局部变量是不可能的,所以出现了闭包这种形式,在函数内部再定义一个函数。
查阅了一些文章和资料,发现还是下面的定义最容易理解:
闭包:定义在函数内部的一个函数。
扩展一些讲,可以参考一下阮一峰的讲解:
闭包:能够读取其他函数内部变量的函数。
俗话说的好,看定义不如看代码更直观一些,如下
function f1(){
var n=999;
function f2(){
console.log(n);
}
return f2;
}
var result=f1();
result(); // 999
如此段代码所示,f2()
就是其中的闭包函数,通过f2()
我们可以访问到f1()
内部的n
。
更常见的一种简写形式:
function f1(){
var n=999;
return function(){
console.log(n);
};
}
var result=f1();
result(); // 999
优点:
缺点:
var a = 1;
function foo(){
var a = 2;
c = 0;
return function () {
console.log(a);
console.log(b++);
console.log(c);
}
}
console.log(a);// 1
//console.log(c); // Reference Error
var b = 3;
var x = foo();
x(); //2 3 0
console.log(a); // 1
console.log(b); // 4
console.log(c); // 0
function fun(n,o) {
console.log(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1); c.fun(2); c.fun(3);
看解答前先思考一下会输出什么哦
【解答】: 首先对函数进行分析,这个函数其实是返回了一个对象,{fun:function(){}}
,里面有一个函数作为属性,这个函数就是闭包,使得函数内部的变量保留在内存中。
注意,这里会有一个可能误解的地方,return {fun:...}里面的fun是fun(n,o)吗?明白这个区别后后面就容易多了。
好了,明白大概的原理后,我们来分析这个问题:
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
执行a = fun(0)
,0是作为n传入的,o没有参数传入,所以输出undefined,之后,
a = {
fun:function(m){
return fun(m,0);//这里的n应该变成了第一次调用时的参数n,也就是0
}
}
也就是
a = {
fun:function(m){
return function(n = m, o = 0) {
console.log(o) //输出0
return {
fun:function(m){
return fun(m,n);
}
};
};
}
}
所以无论传入的m是什么,输出永远都是0 最后,输出结果如下
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
undefined
0
0
0
搞清楚第一个的过程,第二个的破解关键就在于闭包让函数内部的变量始终保存在内存之中。
//b
undefined
0
1
2
//c
undefined
0
1
1
《学习Javascript闭包(Closure) - 阮一峰的网络日志》 《闭包 - 廖雪峰的官方网站》