JavaScript入門學習之旅(一)——JavaScript變數提升和函式提升

清風匝地發表於2017-04-21

在JavaScript引擎正式編譯之前,會進行一次預編譯,在這個過程中,會將變數宣告及函式宣告提升至當前作用域的最頂端,其後才進行接下來的處理。

變數提升

未使用塊級作用域:

原始碼:

console.log(msg);// undefined
var msg = "This is a message";
console.log(msg);// This is a message

function fn () {
  console.log(hello); // undefined
  var hello = 'hello world';
  console.log(hello); // hello world
}
fn();

JavaScript解析器的解析流程:

var msg;// 變數提升,全域性作用域範圍內,此時只是宣告,並沒有賦值
console.log(msg);// undefined
 msg = "This is a message";// 此時才賦值
console.log(msg);// 列印出This is a message

function fn () {
    var hello;// 變數提升,函式作用域範圍內,此時只是宣告,並沒有賦值
  console.log(hello); // undefined
  hello = 'hello world';// 此時才賦值
  console.log(hello); // hello world
}
fn();

ES5只有全域性作用域和函式作用域,而ES6開始提供了塊級作用域。使用ES6語法的let建立的變數和const語法建立的常量,均不存在變數提升。

使用塊級作用域:

console.log(msg);//Uncaught ReferenceErrord
let msg = "This is a message";//沒有被執行
console.log(msg);//沒有被執行

function fn () {
  console.log(hello); //Uncaught ReferenceErrord
  let hello = 'hello world'; //沒有被執行
  console.log(hello); //沒有被執行
}
fn();

IIFE與塊級作用域

一般的JavaScript函式有三種寫法。

1.函式關鍵字,也叫函式宣告語句寫法

function foo(){}; foo();

2.函式字面量,也叫函式表示式寫法

var foo = function(){}; foo();

3.funtion()建構函式

var foo = new function(): foo();

有時需要在定義函式之後,立即呼叫該函式。這種函式就叫做立即執行函式,全稱為立即呼叫的函式表示式IIFE(Imdiately Invoked Function Expression)。 通過立即呼叫的函式表示式,能夠實現塊級作用域的效果。

JavaScript引擎規定,如果function關鍵字出現在行首,一律解釋成函式宣告語句,而且宣告語句必須要有一個函式名。所以如下的程式碼demo會報錯。

function () {}; //Uncaught SyntaxError: Unexpected token (

正確的寫法是給函式宣告語句提供一個函式名。

function foo() {}; //undefined

接下來將函式宣告語句與JavaScript分組操作符進行組合,看上去這樣的組合好像並沒有什麼意義,並且會丟擲一個錯誤:

function foo() {} (); //Uncaught SyntaxError: Unexpected token )

錯誤在於JavaScript分組操作符需要指定一個值,不能為空。

正確的組合寫法:

function foo() {} (0);//0

function foo() {}; (0); //0 兩種寫法等價。

這樣也僅僅是實現了函式宣告語句與不報錯的分組操作符的組合。

所以需要將函式宣告語句改成函式表示式寫法,將function使用分組操作符進行組合。這樣就不需要再指定一個函式名。這個表示式將會在載入網頁時立即執行,而不需要單獨呼叫函式。執行後,函式內程式碼塊宣告的變數將只在區域性作用域內有效。無法被外層訪問到。

(function () {} () );

或者

(function () {}) ();

在ECMAScript6中,由於塊級作用域的出現,實際上使得獲得廣泛應用的立即執行函式表示式(IIFE)不再必要了。

// IIFE 寫法 
(function () { var tmp = 0; }());



// 塊級作用域寫法
{ let tmp = 0; }

函式提升

函式提升與變數提升效果一致,但JavaScript只有函式宣告語句才存在函式提升.

原始碼:

console.log(msg1); // function msg1() {};
console.log(msg2); // undefined
function msg1() {}
var msg2 = function() {}

JavaScript解析器的解析流程:

function msg1() {}; // 函式提升,整個程式碼塊提升到檔案的最開始
console.log(msg1);
console.log(msg2);
var msg2 = function() {}

參考來源:

深入理解閉包系列第三篇——IIFE

ECMAScript 6 入門

任務一:零基礎JavaScript編碼(一)

相關文章