javascript中ES5的var、function,ES6的function *、let、const、class會被提升,但是var、function、function *和let、const、class的的提升並不相同。
本文只討論ES5中變量提升,ES6中變量提升
ES5變量提升
首先了解js的執行環境和作用域
執行環境
執行環境定義了變量和函數有權訪問的其他數據,決定了他們各自的行為。每個執行環境都有與之對應的變量對象(variable object),此對象保存着環境中定義的所有變量和函數。我們無法通過代碼來訪問變量對象,但是解析器在處理數據時會在后台使用到它。
-全局執行環境
全局執行環境是最外圍的一個執行環境,根據ECMAscript實現所在的宿主環境不同,表示執行環境的對象也不同。在web瀏覽器中,我們可以認為它是window對象,因此所有的全局變量和函數都是作為window對象的屬性和方法創建的。代碼載入瀏覽器時,全局環境被創建,應用程序退出,如關閉網頁或者瀏覽器時,全局執行環境被銷毀。
-函數執行環境
每個函數都有自己的執行環境,當執行流進入一個函數時,函數的環境就被推入一個環境棧中,當函數執行完畢后,棧將其環境彈出,把控制權返回給之前的執行環境。
作用域
在ES5中,js只有兩種形式的作用域:全局作用域和函數作用域。
-全局作用域
全局對象的作用域,任意地方都可以訪問到(如果沒有被函數作用域覆蓋)。在ES6中,新增了一個塊級作用域(最近的大括號涵蓋的范圍),但是僅限於let方式申明的變量。
-函數作用域
整個函數范圍
作用域鏈
變量提升(hoisting)
ES5 提升有變量提升和函數提升。
原則:
1、所有申明都會被提升到作用域的最頂上;
2、同一個變量申明只進行一次,並且因此其他申明都會被忽略;
3、函數聲明的優先級優於變量申明,且函數聲明會連帶定義一起被提升。
-變量提升
把變量聲明提升到函數的頂部,但是變量賦值不會提升。
console.log(a); var a = 10; //輸出為undefined /************/ var a; console.log(a); a = 10; //與上例等價
function add(){ y = 10; var y = 1; console.log(y); } add(); //輸出1
注意:變量未聲明,直接使用,輸出‘變量 is not defined’。
-函數提升
函數提升會將函數聲明連帶定義一起提升。
在JavaScript中函數的創建方式有三種:函數聲明、函數表達式(函數字面量)、函數構造法(動態的,匿名的)。只有函數聲明創建的函數會執行函數提升,字面量定義的函數(實質為變量+匿名函數)會執行變量提升。
test1(); function test1(){ console.log("可以被提升"); }
test2(); var test2 = function(){ console.log("不可以被提升"); }
console.log(test2); var test2 = function(){ console.log("不可以被提升"); }
函數和變量同時提升
console.log(test3); function test3(){console.log('func');} var test3 = 'Mary';