## 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 原生函数