JS原理 - 变量提升

变量提升(Hoisting),是指在JavaScript代码执行过程中,JS 引擎把变量的声明部分和函数的声明部分提升到代码开头的行为。

要理解变量提升的概念,首先要知道 JS 引擎运行代码时,会对代码进行块级解析然后执行,而非未经解析就逐行执行。在编译阶段,变量和函数会被存放到变量环境中,变量的默认值会被设置为 undefined;在代码执行阶段,JS 引擎会从变量环境中去查找自定义的变量和函数。

然后分清什么是声明?什么是赋值?

var a = "hello";
// 等同于
var a;  // 声明部分
a = "hello";  // 赋值部分
function foo(){};  // 完整的函数声明,没有涉及到赋值操作

var foo = function(){};
// 等同于
var foo;  // 声明部分
foo = function(){};  // 赋值部分

其中var afunction 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
作者

BiteByte

发布于

2022-12-20

更新于

2024-01-11

许可协议