一、全局变量和局部变量
// 全局变量:可以在任意位置访问的量就叫全局变量
// 全局变量从创建的那一刻起就会一直保存在内存中
var age = 20;
function a(){
console.log(age);
}
a(); //20
// 局部变量:比如函数中用var定义的变量,只能在函数中访问这个变量,函数外部访问不了
// 局部变量当函数运行完以后就会销毁这个变量
function b(){
var age = 20;
}
console.log(age); // Uncaught ReferenceError: age is not defined
二、什么是闭包?
2-1 闭包原理
闭包是基于正常的垃圾回收处理机制下的,也就是说,一般情况一个函数(函数作用域)执行完毕,里面声明的变量会全部释放,被垃圾回收器回收。但闭包利用一个技巧,让作用域里面的变量,在函数执行完之后依旧保存没有被垃圾回收处理掉。
2-2 闭包优缺点
优点:方便调用上下文中声明的局部变量,逻辑紧密,可以在一个函数中再创建个函数,避免了传参的问题
缺点:因为使用闭包,可以使函数和变量在执行完后不被销毁,保留在内存中,如果大量使用闭包就会造成内存泄露,内存消耗很大
三、常见的闭包写法
3-1 闭包的形成
在嵌套函数中,父函数调用后返回一个子函数,并且返回的这个子函数使用了父函数作用域定义的局部变量,导致该变量在父函数执行完毕后并没有被垃圾回收机制回收,从而形成了一个闭包
function bar(){
var num = 0;
function foo(){
num ++;
console.log(num);
}
return foo;
}
var f = bar();
f(); //1
f(); //2
代码解析:在bar函数中,声明一个变量num,他属于bar函数作用域下的变量。bar函数返回一个foo函数,这个函数被嵌套,函数内部弹出num。首先执行var f = bar();那么bar就执行了,但是执行完毕之后,num变量并没有被释放回收,因为bar函数返回值里面还等待使用这个变量,这个时候foo()就是包含bar()内部作用域的闭包,使得该作用域能够一直存活,不会被垃圾回收机制处理掉,这就是闭包的作用,以供foo()在任何时间进行引用。
var a = (function(){
var num = 0;
function b(){
num ++;
console.log(num);
}
return b;
})();
a(); //1
a(); //2
四、闭包经典场景
var btnList = document.getElementsByClassName("btn")
for(var i = 0; i < 6; i++){
btnList[i].onclick = function(){
console.log("第"+i+"个按钮被点击到了")
}
}
//无论点哪个btn,打印的都是“第6个按钮被点击到了”
var btnList = document.getElementsByClassName("btn")
for(var i = 0; i < 6; i++){
(function(j){
btnList[j].onclick = function(){
console.log("第"+j+"个按钮被点击到了")
}
})(i)
}
//for循环每一次都执行一个自执行函数,每一次变量 i 被当做参数传到自执行函数中去,那么这个自执行函数相当于每次创建了一个变量就是参数 j ,然后第j个元素节点 btnList 绑定一个onclick事件,执行函数里面需要用到这个参数 j ,但是你又没点 , 所以 j 就没有被清理 , 就一直在参数里面被保存着 , 每一个自执行函数都做一样的事情 ,所以这个时候就产生了闭包 ,变量 j 并没有被回收,依然在等待你使用。