举几个例子记录一下,JS的执行时机,有点容易搞混。
🌰 1:
let a = 1
function fn(){
console.log(a)
}
打印出多少? 1吗?❌
但是不打印,因为没有调用函数。
🌰 2:
let a = 1
function fn(){
console.log(a)
}
fn()
打印出多少?1吗?✅
比上一个例子多了一个调用,打印出1。
🌰 3:
let a = 1
function fn(){
console.log(a)
}
a=2
fn()
打印出多少?1吗?❌
声明变量a并且赋值为1,声明函数fn,再把2赋值给a,调用fn,打印a的值为2。
🌰 4:
let a = 1
function fn(){
console.log(a)
}
fn()
a=2
打印出多少?1吗?✅
比起上一个例子,是先调用函数fn打印出了a的值为1,再把2赋值给a。
从以上几个例子可以总结出:确定函数运行的结果,需要关注函数执行的时间前的代码。因为后面的代码还没执行,不会影响函数的运行结果。
再看几个异步例子: 🌰 5:
let a = 1
function fn(){
setTimeout(()=>{console.log(a)},0)
}
fn() // 2
a = 2
setTimeout过一会儿执行,执行顺序是在把2赋值a之后才执行打印a的值。
再来看一个经典面试题,方便查看我就标记一个🌰 6啦:
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
i的结果是?
答案是6个6,声明i是一个全局变量,只有一个i的值。整个过程当i满足条件循环的时候,setTimeout并没有执行,最后到满足条件的时候i的值为6,并且执行了6次setTimeout打印出a,所以结果是6个6.
那如果想要打印出0,1,2,3,4,5呢?请看下面的🌰 7:
for (let i = 0,i<6,i++){
setTimeout(()=>{
console.log(i)
},0)
}
因为在for语句里用let声明变量是局部变量遵循块作用域,所以每次for循环执行时都会生成一个单独的作用域,也会生成一个新的i,相当于有6个i。 此时,每次执行setTimeout()时都会打印出对应的i,打印结果就是0、1、2、3、4、5了。
最后一个例子,
function f1(){
let a = 1
function f2(){
let a = 2
function f3(){
console.log(a)
}
a = 22
f3()
}
console.log(a)
a = 100
f2()
}
f1()
最后会打印出多少呢?是1和22。