啊啊啊啊!!!
JS中的重难点来了,让我哭一会....
闭包 — — — —面试必考点、JS必须务必掌握的知识点!!!
灵魂拷问第一问:什么是闭包?
弄清闭包之前我们要先了解什么是“函数作用域”
- 函数作用域
1.1、全局变量:就是声明在函数外部的变量,无论在代码的任何位置都能访问到的对象,他们就拥有“全局作用域”(所有没有用var定义的变量也属于全局变量)
(1)最外层函数and在最外层函数外面定义的变量
例如:
var a="啦啦啦";//声明在函数最外部
function b(){ //最外层函数b
var c="咚咚";
function d(){
alert(c);
}
d();
}
alert(a); //啦啦啦
alert(c); //报错
b(); //咚咚
d() //报错
如上例中,a是定义在函数最外部的所以在最后输出它就可以获得到,同样function b是定义在最外层的函数最后也可以执行获取定义的,而function d()就不行了,它是在b();里面定义的最后在外部不可以访问到。
(2)未定义的变量也属于全局变量拥有全局作用域
例如:
function b(){ //最外层函数b
var c="咚咚";
d = "呀呀"
alert(c);
}
b();// 咚咚
alert(d); //呀呀
alert(c);//报错
如上例中,function b(){}是定义在外层函数,d是没有用字面量定义的变量,所以function b(){}和d都拥有全局作用域,而在函数内部定义的c却无法访问到,c就属于局部变量。
(3)所有window对象的属性拥有全局作用域
1.2、 局部变量:它与全局作用域相反,声明在函数内部的变量,特点就是只有在他声明的函数内部才可以访问到,出了那个函数的范围便无法访问。 如上的例子可以看到那些程序之所以报错就是因为在他的局部范围外访问他,导致无法访问到他。
通过上面的介绍大家应该都明白了作用域是怎么回事,那么闭包就好理解了,刚刚提到一个局部的作用域只能在他的函数范围内才能访问到他,我们可以把能访问到他范围的空间当做一个封闭的空间。
在函数中定义一个变量,这个变量只要超出这个函数范围就找不到了,在程序中,如果这个函数执行完成,那么这个封闭的空间就会销毁。而如果想不让他被销毁就是形成“闭包”。
闭包就是内部函数引用着外部的函数的变量,外部的函数尽管执行完毕,作用域也不会销毁。从而形成了一种不销毁的“闭包”。
用个例子来更加鲜明的解释它:
function fn(){
var a = 1;
return function(){
console.log(a);
}
}
通过上面例子可以看出闭包是咋回事了,其实简单解释,就是在一个函数里在定义一个函数。这个内部函数一直保持有对外部函数中作用域的访问限权。(把函数看成盒子,就是外面的大盒子一直可以被小盒子所访问,小盒子一直有大盒子的访问限权)
函数执行,形成一个私有的作用域,保护里边的私有变量不受外界的干扰,除了保护私有变量外,还可以存储一些内容,这样的模式叫做闭包。
- 那么闭包的作用是什么呢?
保护和保存————保护一些私有的变量,只有他们可以访问,保存就是保存函数内容,重复使用变量却不会让这个变量受污染,受改变。
来一个闭包的实例,更加鲜明的理解一下吧
function fn1() {
var name = 'iceman';
function fn2() {
console.log(name);
}
return fn2;
}
var fn3 = fn1();
fn3();
这个函数就是形成了一个闭包。上中,fn2的词法作用域可以访问到fn1的作用域,然后将fn2当做一个值返回,当fn1执行后,将fn2的引用赋值给fn3,然后执行fn3,就输出了变量name。
正常来说,当fn1函数执行完毕之后,其作用域是会被销毁的,然后垃圾回收器会释放那段内存空间。而闭包却很神奇的将fn1的作用域存活了下来,fn2依然持有该作用域的引用,这个引用就是闭包。