JS 函数的执行时机

89 阅读2分钟

举几个例子记录一下,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。