1.闭包的理解
之前面试的时候老是问到闭包,也经常答得差强人意,为什么呢?我觉得是因为没有看过权威的解释,面试完不会了,就去百度上随便找了一个答案,然后就认为自己懂了。其实,每个人在读完知识点的时候,都会加上一些自己的理解,可能第一个人理解了,但是写出来的东西只能表达到90%,第二个人读了第一个人的理解就只能了解到70%,而到我…就会让面试官感觉,我完全不理解,简直就是在瞎说一通。
所以,我今天找了几个关于闭包的权威解释:
《JavaScript权威指南》这样描述:
闭包是指有权访问另一个函数作用域中的变量的函数;
《JavaScript权威指南》这样描述:
从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。
你不知道的《JavaScript》这样描述:
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
我个人目前比较赞同第一种! 接下来上代码!
看一段代码(可能不太好观察)
function fn1() {
var name = 'zaoren1';
function fn2() {
console.log(name) //zaoren1
}
fn2();
}
f1();
可以看到,我们在fn2的作用域中,可以访问到fn1作用域中的name,这就是闭包(什么?! 你是不是经常这样干?原来,我几乎每天都在使用闭包,我也太强了把!)
再看一段代码
function fn1() {
var name = 'zaoren2';
function fn2() {
console.log(name);
}
return fn2;
}
var fn3 = fn1();
fn3();
我们知道通过引用的关系,fn3就是fn2函数本身。执行fn3能正常输出name,这不就是fn2能记住并访问它所在的词法作用域,而且fn2函数的运行还是在当前词法作用域之外了。
正常来说,fn1函数执行完毕的时候,其作用域是会被销毁的,然后垃圾回收机制会释放内存空间。而闭包却很神奇的将fn1的作用域存活了下来,fn2依然持有该作用域的引用,这个引用就是闭包。
2.闭包的使用场景
场景一: 给setTimeout加参数
// setTimeout的第一个参数为函数对象,该对象不支持传参,可以使用闭包,让setTimeout能访问waitSomeTime作用域下的变量
function waitSomeTime(msg) {
var param = msg;
setTimeout(() => {
console.log(msg)
}, 1000);
}
waitSomeTime('hello');
场景二: 定义模块时,将操作的接口暴露出来,细节隐藏在内部
function module() {
var core = [];
function add(num) {
core.push(num);
}
function get(index){
return core[index];
}
return {
add,
get,
}
}
var mod = module();
mod.add(1);
mod.add2(2);
mod.get(1);
感觉这样也可以实现函数内部变量的私有化(core相当于就是module的私有属性了,不能直接访问)