参考文章:深入理解javascript原型和闭包(完结) ,链接里的内容讲解的很详细。我的这篇文章为了尽量把结合自己的理解用文字记录下来。
说闭包之前,要提到变量和作用域。
变量分为全局变量和局部变量。全局变量也就是函数外部声明的变量,如果一个变量没有用var声明,则会被识别为全局变量。比如name = 'Mike';
局部变量是函数内部的变量,函数执行完之后就消失。
作用域也分为全局作用域和函数作用域,js没有块级作用域。
当函数内部的变量值会优先在函数声明时的作用域寻找,并非调用时候的作用域(很关键)!!!
在内部未找到的变量声明时会到父级作用域中去找,如果还没找到继续往父级找直到全局作用域。
函数如果在自身内部作用域有重新声明,同名的全局变量会失效,采用的是函数内部作用域里的变量。如
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack'; ///important
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})(); //print Goodbye Jack
此时输出为Goodbye Jack说明typeof name === 'undefined'; 这是因为函数内部重新声明了var name;因此函数值会在函数内部作用域找而非全局作用域。
即使var name ='jack';是在判断之后if (typeof name === 'undefined')才执行的,但是js会把变量的声明提前。相当于
var name;
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye ' + name);
}
函数作为返回值:
function out(){
var num=0;//内部变量
return function add(){//通过return返回add函数,可以在out函数外访问了。
num++;
console.log(num);
};
}
var func1=out();//
func1();//实际上是调用add函数, 输出1
func1();//此时是输出是2,说明执行一次过后num值变为1,而普通函数执行完之后,上下文环境(当前作用域的变量)就消失了。
var func2=out();
func2();// 输出1,重新声明的func2起作用,num又重新从1开始,num并非像全局变量改变了。
func2();//
再来一个返回值的例子:
var data = [];
for (var k = 0; k < 3; k++) {
data[k] = (function test(x) {
return function () {
console.log(x);
};
})(x);
}
data[0]();//1
data[1]();//2
data[2]();//3
函数作为参数传递
var max=10,
fn = function (x){
if(x > max){
console.log(x);
}
};
(function (f){
var max=100;
f(15);
})(fn); //10 去函数创建的作用域取值
上面的例子中,
fn函数作为一个参数被传递进入另一个函数,赋值给f参数
通过参考一些文章和自己的尝试,我的理解是闭包像是把函数内的局部变量缓存起来,在函数执行完依旧存在,但是外部又无法直接访问,得通过执行函数来访问。其实就是函数调用完成之后,其执行上下文环境不会接着被销毁。