JS 函数的执行时机

200 阅读3分钟

在开发过程中,JS 函数的不同执行时机,会直接影响到函数的输出结果。

先举几个简单的例子吧:

例 1

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

这段代码中,无法打印出 1 ,因为根本就没有调用函数的代码。

例 2

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

通过 fn()调用了函数,所以执行console.log(a),打印出 a 的值:1。

例 3

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

这段代码中在调用函数前赋予了 a 一个新的值:2,所以执行后会打印出 2。

例 4

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

这段代码在调用函数之后才赋予了 a 一个新的值:2,所以执行后还是打印出调用函数时 a 的值:1。

(一定要注意不能陷入固定的思路中,并非let a = 1后 a 的值就一定是 1 ,它只是声明了一个 a 而已,a 的具体取值要看 a 被赋予了什么值以及函数的执行时机才行)


接下来是课题:

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

这段代码中,因为加了setTimeout()的缘故,不会依次打印出 0-5 而是打印 6 个 6。

原理

setTimeout()是一个异步任务,执行到这里的操作会被浏览器丢到另一个任务队列里去,浏览器这时候会继续往下执行,把下面的代码都执行完了才会来执行 setTimeout 函数里的操作(摘自别人的博客)。

这句话可理解为“尽快调用函数--完成手头正在进行的任务后立刻执行,而不是看到一次执行一次”。因为设置了setTimeout()的缘故,整个代码的循环方式变成了“在 i 的值已经变成 6,for 循环结束之后,再执行 6 次console.log(i)”的情况。因为在最后执行console.log(i)之前,i 的值已经变成了 6,所以这段代码执行的结果是 6 个 6 而非 0-5。


如果想要打印出 0、1、2、3、4、5 ,方法也有很多,整理了几个在这篇博客,说不定以后能用到 233:

方法 1

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

原理:将定义 i 的let i = 0放入 for 循环中,在每次进行 for 循环的时候,都会生成一个新的 i,setTimeout()中输出的 i 就是这个新的 i,所以能够输出正常的 0-5。

方法 2

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

原理:用到了闭包--即将一个函数要用到的变量放到外部,或者说这个函数用到了外部的变量,这个函数和这个变量就叫闭包。这段代码中适用立即执行函数的知识定义了一个匿名函数,将 for 循环中的 i 当做 value 传入输出,可以打印出 0-5。

方法 3

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

原理:使用了 setTimeout 的第三个参数--这个参数可以将自身传给第一个参数 function,即将 i 作为第三个参数传给函数当做 value 打印出来,即可打出 0-5 了。

目前能整理出的就这三种方法。。如果在以后的学习过程中想到了或者找到了其他方法,我会补充在这里。。。

果然山的那边还是山,越过层峦才能看海,继续努力吧。