变量提升
准确的说应该是 变量声明提升
// 例1
a = 100
var a
console.log(a) // 100
// 例子2
console.log(a) // undefined
var a = 300
conole.log(a) // ReferenceError: a is not defined
a = 300 // 因为 a 并没有声明var 所以不提升
通过前面的3个代码片段来深入探讨一下js的提升。
包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。
当你看到 var a = 100; 时,可能会认为这是一个声明。但 JavaScript 实际上会将其看成两个 声明:var a;和a = 100;。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在 原地等待执行阶段。所以第一个例子中的代码会进行如下处理
// 例1的编译执行过程
var a
a = 100
console.log(a) //100
var a
console.log(a) //undefined
a = 300
这个过程就叫作提升, 变量声明在编译的时候从它们在代码中出现的位置被“移动” 到了最上面。 注意:只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。
函数提升
准确的说应该是 函数声明提升, “声明”这两个字很重要哈!!
demo();
function demo() {
console.log( a ); // undefined
var a = 2;
}
上面的代码demo()函数提升了
function demo() {
var a // 注意每个作用域都会进行提升操作!
console.log( a ); //undefined
a = 2
}
demo()
可以看到,demo()作用域里面也会进行提升,每个作用域都会进行提升操作!
函数声明会被提升,但是函数表达式却不会被提升。
demo() // TypeError: demo is not a function
var demo = function() {
var a = 2
console.log(a)
}
上面这个代码片段不会跑出 reference error 是因为 demo 变量声明被提升到了顶部, 但是 demo 此时并没有赋值(如果它是一个函数声明而不是函数表达式,那么就会赋值)。demo() 由于对 undefined 值进行函数调用而导致非法操作, 因此抛出 TypeError 异常。
demo() // TypeError: demo is not a function
demo1() // ReferenceError: demo1 is not defined
// 具名的函数表达式demo1,名称标识符在赋值之前也无法在所在作用域中使用
var demo = function demo1() {
console.log("demo1 func")
}
上面的代码被提升之后的可以理解为
var demo
demo() // TypeError: demo is not a function
demo1() // ReferenceError: demo1 is not defined
demo = function() {
var demo1 = this
}
函数优先
函数声明和变量声明都会被提升, 函数会首先被提升,然后才是变量
demo() // demo
var demo // 这个在demo函数声明前面,但是函数提升会优先,但它是重复的声明因此被忽略了
function demo() {
console.log("demo")
}
// 尽管重复的var声明会被忽略掉,但出现在后面的函数表达式还是可以覆盖前面的。
demo = function () {
console.log("demo1")
}
demo() // demo1
demo(); // "b"
var a = true;
if (a) {
function demo() { console.log("a"); }
} else {
function demo() { console.log("b"); }
}
注意: 但是在node.js中上面的代码试了一下,这里会抛出TypeError: demo is not a function。 node.js 版本v10.0.0. 有时间再去研究一下,应该是node.js 对if 块 进行了函数提升的限制, 只提升变量demo。 如果有人知道答案可以留言给我,最好给个连接地址啦。
总结:
无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行编译处理。 可以将这个过程形象地想象成所有的声明(变量和函数)都会被“移动”到各自作用域的最顶端,这个过程被称为提升。
声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。 要注意避免重复声明,特别是当普通的 var 声明和函数声明混合在一起的时候,否则会引起很多危险的问题!