JS原理 - 变量提升
变量提升(Hoisting),是指在JavaScript代码执行过程中,JS 引擎把变量的声明部分和函数的声明部分提升到代码开头的行为。
要理解变量提升的概念,首先要知道 JS 引擎运行代码时,会对代码进行块级解析然后执行,而非未经解析就逐行执行。在编译阶段,变量和函数会被存放到变量环境中,变量的默认值会被设置为 undefined;在代码执行阶段,JS 引擎会从变量环境中去查找自定义的变量和函数。
然后分清什么是声明?什么是赋值?
var a = "hello";
// 等同于
var a; // 声明部分
a = "hello"; // 赋值部分
function foo(){}; // 完整的函数声明,没有涉及到赋值操作
var foo = function(){};
// 等同于
var foo; // 声明部分
foo = function(){}; // 赋值部分
其中var a
和function foo(){}
这两个声明部分会被提升,而a = "hello"
和foo = function(){}
这两个赋值部分不会被提升。
那么下面代码的输出就很好理解了:
console.log(name); // undefined
say(); // "A"
foo(); // throw Error: foo is not a function, 此时 foo 是 undefined 不能被执行
var name = "Mike";
function say(){ console.log("A") };
var foo = function(){ console.log("B") };
那如果出现函数和变量同名的情况呢?
需要记住一个概念:变量提升(编译阶段)时,函数声明会覆盖变量声明,但不会覆盖变量的值,在执行阶段,后定义的会覆盖之前定义的。看个例子:
console.log(foo);
function foo() {};
var foo = 2;
console.log(foo);
// 等同于
var foo;
fucntion foo(){}; // 变量提升
console.log(foo); // f foo() {}
foo = 2;
console.log(foo); // 2
再来看个例子:
foo();
var foo = function() {
console.log('foo1');
}
foo();
function foo() {
console.log('foo2');
}
foo();
// 等同于
var foo = undefined;
function foo() {
console.log('foo2');
}
foo(); // foo2
foo = function() {
console.log('foo1');
}
foo(); // foo1
foo(); // foo1
需要注意的是,变量提升并不是提到所有代码的顶部,如果变量在函数内部,则会被提升到当前函数的顶部。
看个例子:
var foo = 1;
function bar() {
if (!foo) { var foo = 10 };
console.log(foo);
}
bar();
// 等同于
var foo;
foo = 1;
function bar(){
var foo; // foo is undefined
if(!foo) { foo = 10 };
console.log(foo);
}
bar(); // 10
JS原理 - 变量提升