JS 函数的执行时机

前言

记录下 js 函数的执行时机,困扰了我很久。面试

案例

咱们一个一个例子的来看promise

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

// 不会打印任何东西,由于函数没有执行
复制代码
let a = 1
function fn(){
    console.log(a)
}
fn() // 1 
//很简单,一开始声明了 a , a 的值为1,而后调用函数 fn , 打印 a。 
复制代码
let a = 1
function fn(){
    console.log(a)
}
a = 2
fn() // 2
// 一开始声明了 a , a 的值为1,而后在函数以前将 2 赋值给 a 。 因此打印出 a 的值为2。
复制代码
let a = 1
function fn(){
    console.log(a)
}
fn() // 1
a = 2
// 此次是在函数执行后改变 a 的值,函数执行的时候,a 的值依旧为1.
复制代码

经过上面几个例子能够看出,函数中某个变量值的判断,须要肯定函数执行的时机。一开始声明的时候多是某个值,但在函数执行的时候这个值可能已经改变了。bash

再来看几个 异步的例子。闭包

let a = 1
function fn(){
    setTimeout(()=>{
        console.log(a)
    },0)
}
fn() // 2
a = 2
复制代码

这个结果是为2。由于setTimeout函数会在队列任务执行完后再执行。因此等到打印 a 的时候值已经变为2了。异步

再来看个经典面试题:函数

for(var i = 0; i<6; i++){
    setTimeout(()=>{
        console.log(i)
    },0)
}
// 会打印出 六个六。
复制代码

这至关于post

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

由于 i 是全局的。for 循环执行完毕以后 i 的值为6。有人奇怪 i 不该该是5吗。i = 5 知足条件(<6)是最后一轮循环,而后i++,i 为6。这个循环自始至终都是在改变一个 i 的值。因此会打印6个6。ui

那我就是想要符合预期的打印0、一、二、三、四、5呢?能够这样:spa

for(let i = 0; i<6; i++){
    setTimeout(()=>{
        console.log(i)
    },0)
}
// 0 1 2 3 4 5
复制代码

这里 let 会单首创建一个做用域 至关于有6个 i 。code

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

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

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

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

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

复制代码

咱们还能够这样解决:

for (var i = 0; i < 6; i++) {
    setTimeout((function(i){
        return function() {
            console.log(i);
        }
    }(i)),0)
}
// 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()
复制代码

这里有不少 a ,a 有不少值。咱们只须要肯定咱们打印a的时候,a 是哪一个 a 以及 a 是什么值。答案是1和22

执行 f1 函数的时候一开始第一个 a 为1,而后有个 f2 函数没执行就先跳过。而后打印 a 。因此咱们能够肯定打印的值为 1 。而后 a = 100 没卵用。

再而后执行 f2 函数。f2 函数中声明了 a = 2 。而后有个 f3 函数没执行就跳过。而后 a = 22。因此以前声明的那个 a 就是22。而后执行 f3 函数。打印 a 为22。就是这么简单,这就是闭包,函数和函数内部可以访问到的函数外的变量。

最后

最后确定还有更加复杂的 setTimeout + promise + nextTick的执行顺序,涉及了宏任务跟微任务(其实很是简单)

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
复制代码

这里是引用的另一个大佬的啦,有兴趣能够戳这里哦

相关文章
相关标签/搜索