我們知道JS代碼在執行之前,會做一系列的事情,其中就包括變量提升,原本以爲把變量提升搞懂的我(因爲這兩天一直在研究變量提升,自我感覺已經很良好了,哈哈哈),拿到了一道打臉的題。當然了,拿給身邊的程序員朋友們,做對的也......廢話不多說,一起來看下這道題吧。
1. 題目
var a = 0;
if (true) {
a = 1;
function a() {};
a = 21;
console.log(a)
}
console.log(a);
答案:21 1
2. 重新學習變量提升
2.1 var
首先說使用var
聲明的變量,只要那個變量是使用var
聲明的,那麼在變量提升階段要做的事情只有一個,就是去聲明這個變量。
一道簡單的題目看懂var
的變量提升
console.log(a);
var a = 1;
console.log(a);
在代碼執行之前先創建一個變量a;此時並不會進行賦值等操作 代碼執行 console.log(a);
因爲此時已經有a這個變量了,只不過沒有賦值,因此輸出undefinedvar a = 1;
給變量a進行賦值爲1console.log(a);
這時候再輸出a的值,就是上面的賦值結果1
控制檯查看輸出結果
2.2 let const
我們知道使用let和const聲明的變量沒有變量提升,只有當代碼走到那一行纔會去執行聲明等操作;
2.3 function
當function fn(){...}
沒有在if/for等任何大括號內的時候,它會聲明+定義,即:
把右邊的值存儲在堆內存中,並把堆內存地址存儲在棧內存; 然後聲明變量fn, 最後讓fn和堆地址關聯
但如果把上面的這句話放在if/for
這樣的大括號內的時候,就變成下面這樣的過程了:
聲明一個變量fn存儲在棧內存中 當滿足條件進入到大括號內的時候 第一件事情就是定義這個函數:即讓這個變量名和堆地址進行關聯。注意此時這個變量fn已經變爲這個塊內私有的變量了,和外面的fn沒有任何關係; 當代碼執行過程中,遇到 function fn(){...}
的時候,它會去把全局中的fn修改一下,修改爲堆中fn的值。修改完之後,後面對fn的操作又和全局的fn沒任何關係
3.看穿題目的'廬山真面目'
這道題就是利用上面的所說到function的變量提升情況。即當在if/for中存在函數,並且條件成立,那麼這個函數就變爲私有,直到遇到function fn(){...}
的時候纔會去操作全局的fn,其它情況操作的fn都是私有的。
下面是這道題的圖解過程
4. 同類型題目的練習
{
function foo(){}
foo=1;
}
console.log(foo);
{
function foo(){}
foo=1;
function foo(){}
}
console.log(foo);
{
function foo(){}
foo=1;
function foo(){}
foo=2;
}
console.log(foo);
5. 總結
這也是瀏覽器爲了解決新老版本改善的function的變量提升機制,可以看出也是在一步步的完善,因此我們也要不斷的學習,纔可以跟上互聯網的快速發展。