JS执行时机与闭包
简单来说,JS在执行代函数的时候,由于某些变量的值会改变,所以在不用的时间,不同位置执行函数结果可能会不一样,这就是所谓的执行时机
先看一个简单的例子
let num = 1;
function fn(){
console.log(num);
}
fn(); // 1
num = 2;
fn(); // 2
上面例子说明代码执按照一定的顺序,执行的时机绝对了结果
再看一个例子
for(var i = 0; i<6; i++){
console.log(i);
} // 0 1 2 3 4 5
for(var i = 0; i<6; i++){
setTimeout(()=>{
console.log(i);
},0)
} // 6 6 6 6 6 6
//这里的setTimeout是等一会在执行,具体等多久取决于毫秒参数,但是即使是0,也是等代码执行完成后再来执行这里的代码,因此此时i已经是6了,所以会打出6个6
加下来看这段代码
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
} // 6 6 6 6 6 6
为什么打印出6个6呢?
注意此段代码用let声明的for循环的循环变量i是在全局作用域就定义好的,而setTimeout是等待别的代码执行完毕再执行里面的代码,因此会打印出6个6
要想打印出0 1 2 3 4 5 ,只需要把let声明的i写在for里面即可
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
} // 0 1 2 3 4 5
// let 关键字与 for 循环配合使用会产生奇效,因为在每次循环中,JS会单独创建一个i变量保存在对应的{}作用域中,因此每次循环的值都会被保存下来以便使用,才会有 0 1 2 3 4 5
那么问题来了,我要是非要使用 var 声明变量达到 let 的效果呢?
利用闭包
for(var i = 0; i < 6; i++){
(function(i){ // 这里是立即执行函数
setTimeout(function(){
console.log(i); // 这里便属于用到了闭包
},0)
})(i);
} // 0 1 2 3 4 5
浅谈闭包概念:简单来讲,如果一个函数内使用到了它外部作用域的变量,那么这个函数加上这个变量所构成的一个封闭的环境便是闭包
// 打飞机游戏场景
function begin(){ // 这个函数表示开始游戏
let count = 0; // 表示打掉的飞机数量
return function planeCount(){ // 这个函数表示打落飞机时增加打掉的飞机数量
count++; // 把它返回出去,这样在外部就能改变局部变量count了
}
}
let planeC = begin(); // 在外部用变量接收,同时游戏开始
planeC(); // 每调用一次 飞机数量都加一 除此之外在外部无法改变count的值
由此可以看出闭包的应用简单来说就是隐藏或者是保存局部变量,因为一旦形成闭包,形成闭包的局部变量就不会被JS给垃圾回收掉,即它的值会保存,这是闭包的一个机制