JS函数的执行时机

110 阅读3分钟

我们知道,JS执行时机不同,得到的结果也会不同,这里会以一些简单的例子来做一次整理总结

案例

例1

let a = 1
function fn(){
    console.log(a)
}

这里会打印出什么?
什么也不会打印,因为并没有调用函数

例2

let a = 1
function fn(){
    console.log(a)
}
fn()

这里会打印出什么?
很简单,1,我们在声明了a之后,执行了函数

例3

let a = 1
function fn(){
    console.log(a)
}
a = 2
fn()

这里会打印出什么?
2,因为在执行fn()之前,a被从新赋值为2

例4

let a = 1
function fn(){
  console.log(a)
}

fn()
a = 2

这里会打印出什么?
1,因为在执行fn()之后,a才被从新赋值

在作用域中JS函数的执行时机

例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
因为在f3()中并没有变量a,所以它会向上取最近的作用域f2()中的a,这里的a值为2
但是我们在执行f3()之前,又给a重新赋值了一个新值:22,所以执行f3()打印出的a值为22
而在最外层的f1()中,a的值为1,在下方是先执行console.log(a)之后才重新声明a = 100,所以在这里打印a,值只会是1。

setTimeout

例6

let a = 1
function fn(){
  setTimeout(()=>{
    console.log(a)
  },0)
}
fn()
a = 2

这里会打印出什么?
2,setTimeout会先执行完当前代码,再执行自身,也就是说,在let a = 1,fn(),a=2都执行完之后,才会执行console.log(a)

例7

let i = 0
for(i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

这里会打印出什么?
6个6,同上,setTimeout会先执行完for循环,再打印出i的值,而执行完循环之后,i的值已经变成了6,且这样的循环执行了6次,所以打印出6个6

怎么理解setTimeout?

两个字理解:马上
何为“马上”?
简单的举例,当你正在进行一把激情四射的LOL时,你的母亲大人突然打开你的房门喊你吃饭,你会跟她说“马上就来”。
那么你的“马上”的含义是:

  1. 放下游戏,立刻去吃饭
  2. 打完这一局游戏,再去吃饭 不用想,答案肯定是2,
    所以setTimeout同理,当你让它执行console.log(i)时,它会告诉你“马上执行”,这个“马上”就是等它执行完for循环之后,才会执行console.log(i)

那么应该怎么用for+setTimeout打印出0,1,2,3,4,5呢?

方法1

for(let i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

ES6,引入的新方法,它在每一次循环中,拷贝一个i,把拷贝的i留在setTimeout里,第一次循环把i=0留在里面,第二次留1,以此类推,每次循环生成一个新的i(但其实这么一来,setTimeout也就没有意义了),
可以用如下代码理解:

let i = 0
setTimeout(()=>{
      console.log(i)
    },0)


let i = 1
setTimeout(()=>{
      console.log(i)
    },0)

以此类推

方法2

for( var i = 1 ; i < 6 ; i++ ){
	(function(j){
		setTimeout( function(){
			console.log( j )
		},0)
	})(i)
}

运用立即执行函数,闭包