## 1.4 提升
考慮一下代碼
~~~
a = 2;
var a;
console.log( a ); //2
~~~
~~~
console.log( a ); //undefined
var a = 2;
~~~
### 1.4.1 回憶編譯器
引擎會在解釋JavaScript 代碼之前首先對其進行編譯。編譯階段中的一部分工作就是找到所有的聲明,并用合適的作用域將它們關聯起來。
因此:包括變量和函數在內的所有聲明都會在任何代碼被執行前首先被處理。
對第二段代碼,JavaScript 實際上會將其看成兩個聲明:`var a; 和a = 2;`。第一個定義聲明是在編譯階段進行的。第二個賦值聲明會被留在原地等待執行階段。
即:
~~~
var a;
console.log( a );
a = 2;
~~~
**所有的聲明(變量和函數)都會被“移動”到各自作用域的最頂端,這個過程被稱為提升。**
* 只有聲明本身會被提升,而賦值或其他運行邏輯會留在原地。如果提升改變了代碼執行的順序,會造成非常嚴重的破壞。
* 每個作用域都會進行提升操作。
* 函數聲明會被提升,但是函數表達式卻不會被提升。
~~~
foo(); // 不是ReferenceError, 而是TypeError!
var foo = function bar() {
// ...
};
~~~
* 即使是具名的函數表達式,名稱標識符在賦值之前也無法在所在作用域中使用:
~~~
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() {
// ...
};
~~~
提升后,即
~~~
var foo;
foo(); //typeError
bar(); //ReferenceError
foo = function(){
var bar = ....self...;
//...
}
~~~
### 1.4.2 函數提升
函數聲明和變量聲明都會被提升。但是一個值得注意的細節(這個細節可以出現在有多個“重復”聲明的代碼中)是函數會首先被提升,然后才是變量。
~~~
foo(); // 1
var foo;
function foo() {
console.log( 1 );
}
foo = function() {
console.log( 2 );
};
~~~
盡管重復的var 聲明會被忽略掉,但出現在后面的函數聲明還是可以覆蓋前面的。
~~~
foo(); // 3
function foo() {
console.log( 1 );
}
var foo = function() {
console.log( 2 );
};
function foo() {
console.log( 3 );
}
~~~
一個普通塊內部的函數聲明通常會被提升到所在作用域的頂部,這個過程不會像下面的代碼暗示的那樣可以被條件判斷所控制:(盡可能避免在塊內部聲明函數)
~~~
foo(); // "b"
var a = true;
if (a) {
function foo() { console.log("a"); }
}
else {
function foo() { console.log("b"); }
}
~~~
- 前言
- 第一章 JavaScript簡介
- 第三章 基本概念
- 3.1-3.3 語法、關鍵字和變量
- 3.4 數據類型
- 3.5-3.6 操作符、流控制語句(暫略)
- 3.7函數
- 第四章 變量的值、作用域與內存問題
- 第五章 引用類型
- 5.1 Object類型
- 5.2 Array類型
- 5.3 Date類型
- 5.4 基本包裝類型
- 5.5 單體內置對象
- 第六章 面向對象的程序設計
- 6.1 理解對象
- 6.2 創建對象
- 6.3 繼承
- 第七章 函數
- 7.1 函數概述
- 7.2 閉包
- 7.3 私有變量
- 第八章 BOM
- 8.1 window對象
- 8.2 location對象
- 8.3 navigator、screen與history對象
- 第九章 DOM
- 9.1 節點層次
- 9.2 DOM操作技術
- 9.3 DOM擴展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件處理程序
- 10.3 事件對象
- 10.4 事件類型
- 第十一章 JSON
- 11.1-11.2 語法與序列化選項
- 第十二章 正則表達式
- 12.1 創建正則表達式
- 12.2-12.3 模式匹配與RegExp對象
- 第十三章 Ajax
- 13.1 XMLHttpRequest對象
- 你不知道的JavaScript
- 一、作用域與閉包
- 1.1 作用域
- 1.2 詞法作用域
- 1.3 函數作用域與塊作用域
- 1.4 提升
- 1.5 作用域閉包
- 二、this與對象原型
- 2.1 關于this
- 2.2 全面解析this
- 2.3 對象
- 2.4 混合對象“類”
- 2.5 原型
- 2.6 行為委托
- 三、類型與語法
- 3.1 類型
- 3.2 值
- 3.3 原生函數