關於變量要提前聲明,作為前端程序員我們都知道要這么做。可是為什么要這么做呢?
今天我去面試,被一個面試官問到了這個問題,當時就懵逼了。所以我就研究了一下為什么會變量提升。
研究完才發現,之前有看過這樣的文章,可是沒有真正弄懂。所以寫下了這篇博客。
首先要了解兩個名詞。
JS作用域和詞法分析。
如何了解JS作用域呢? 那么就要了解什么是執行環境。
執行環境:執行環境定義了變量和函數有權訪問的其他數據。每個執行環境都有對應的變量對象(Variable Object),保存着該環境中定義的變量和函數。我們無法通過代碼來訪問它,但是解析器在處理數據的時候會在后台使用到它。
全局執行環境:最外圍的執行環境。我們可以認為是windows對象,因此所有的全局變量和函數都是做為windows的屬性和方法創建的。
局部執行環境:每個函數都有自己的執行環境,當執行流進入到一個函數時,函數的環境就被推入到執行棧當中,當函數執行完畢並且沒有引用時,棧將其環境彈出,將控制權返回給之前的執行環境。
全局作用域:可以在代碼中的任何地方都能被訪問。
局部作用域 : 只有在函數內部才能訪問。
作用域鏈:全局作用域和局部作用域中變量的訪問,其實是由作用域鏈決定的。
&& 每次進入一個新的執行環境,都會創建一個用於搜索變量和函數的作用域鏈。作用域鏈是函數被創建的作用域中對象的集合。作用域鏈可以保證對執行環境有權訪問的所有變量和函數的有序訪問。
&&作用域鏈的最前端始終是當前執行的代碼所在的環境的變量對象,如果該環境是函數,則將其活動對象作為變量對象,下一個變量對象來自包含環境,下一個變量對象來自包含環境的包含環境,依次往上,直到全局執行變量。
&&標識符解析沿着作用域一級一級的向上搜索標識符的過程。搜索過程始終是從作用域的前端逐漸向后回朔,直到找到標識符。
這就是JS的作用域和作用域鏈。
詞法分析:
在JS代碼執行前,會執行詞法分析。所以JS運行要分為詞法分析和執行兩個階段。
函數在運行的瞬間,會生成一個活動對象Active Object,簡稱AO。
- 分析形參
- 如果函數有形參,則給當前活動對象增加屬性,賦值為undefined。
- 分析變量
- 如果AO上還沒有 XXX 屬性,則給當前活動對象增加屬性,賦值為undefined.
- 如果AO上有 XXX 屬性,則不做任何影響。
- 分析函數
- 把函數賦值給 AO.func 屬性
- 如果此前 foo 屬性已存在,則覆蓋。
1 function func(age) { 2 console.log(age); 3 var age = 25; 4 console.log(age); 5 function age() { 6 } 7 console.log(age); 8 9 } 10 func(18);
這是一個函數聲明
首先會進行詞法分析:
- 分析形參
- AO.age = "undefined";
- 分析變量
- Ao.age = 25;
- 分析函數
- Ao.age = function age(){};