JavaScript 變量提高詳解

要點

  1. 引擎會 在解釋 JavaScript 代碼以前首先對其進行編譯。
  2. 編譯階段中的一部分工做就是找到全部的 聲明,並用合適的做用域將它們關聯起來。也正是詞法做用域 的核心內容。
  3. ReferenceError 同做用域判別失敗相關,而 TypeError 則表明做用域判別成功了,可是對 結果的操做是非法或不合理的。
  4. var a = 2提高的是var a;而不會提高賦值操做 a=2,賦值操做將原地保留;

所以,正確的思考思路是bash

  1. 包括變量和函數在內的全部聲明都會在任何代碼被執行前首先 被處理。
  2. 當你看到var a =2;時,可能會認爲這是一個聲明。但JavaScript實際上會將其當作兩個 聲明:
var a;
 a =2;
複製代碼
  1. 第一個定義聲明是在編譯階段進行的。第二個賦值聲明會被留在 原地等待執行階段。

例子1

a = 2;
var a;
console.log( a );//輸出2
複製代碼

由於:函數

var a;
a = 2; 
console.log( a ); // 2
複製代碼

例子2

console.log( a );
var a = 2; //輸出undefined
複製代碼

由於spa

var a; 
console.log( a );
a = 2;
複製代碼

例子3

foo();
function foo() {
    console.log( a ); // undefined 
    var a = 2;
}
複製代碼

foo 函數的聲明(這個例子還包括實際函數的隱含值)被提高了,所以第一行中的調用能夠正常執行。 foo 是函數聲明,函數聲明會被提高,可是函數表達式卻不會被提高。看下面例子4;code

例子4

foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() { // ...
};

複製代碼

由於ip

  1. 這段程序中的變量標識符foo()被提高
  2. 分配給所在做用域(在這裏是全局做用域)
  3. 所以 foo() 不會致使 ReferenceError
  4. 可是 foo 此時並無賦值;(若是它是一個函數聲明而不 是函數表達式,那麼就會賦值)
  5. foo() 因爲對 undefined 值進行函數調用而致使非法操做, 所以拋出 TypeError 異常

因此上面代碼等同於:作用域

var foo;
foo(); // TypeError
bar(); // ReferenceError
foo = function() {
    var bar = ...self... 
    // ...
}

複製代碼

優先級

後面的函數聲明 > 函數聲明 > 變量聲明it

foo(); // 1
var foo;
function foo() {
    console.log( 1 );
}
foo = function() { 
    console.log( 2 );
};
複製代碼

會輸出 1 而不是 2 ! 等同於io

function foo() { 
    console.log( 1 );
}
foo(); // 1
foo = function() { 
    console.log( 2 );
};
複製代碼

總結

要注意避免重複聲明,特別是當普通的 var 聲明和函數聲明混合在一塊兒的時候,不然會引 起不少危險的問題!console

相關文章
相關標籤/搜索