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')
    })
})
複製代碼

這裏是引用的另一個大佬的啦,有興趣能夠戳這裏哦

相關文章
相關標籤/搜索