Skip to content

变量提升

变量提升(Hoisting)被认为是,Javascript 中执行上下文(特别是创建和执行阶段)工作方式的一种认识

从概念的字面意义上说,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。

实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中

函数提升

JavaScript 在执行任何代码段之前,将函数声明放入内存中

js
// 不推荐的方式:先调用函数,再声明函数

catName("Chloe");

function catName(name) {
    console.log("我的猫名叫 " + name);
}
// 不推荐的方式:先调用函数,再声明函数

catName("Chloe");

function catName(name) {
    console.log("我的猫名叫 " + name);
}

TIP

函数和变量相比,会被优先提升,函数会被提升到更靠前的位置

变量提升

只有 var 关键字会有变量提升

JavaScript 只会提升声明,不会提升其初始化。如果一个变量先被使用再被声明和赋值的话,使用时的值是 undefined

js
console.log(num); // Returns undefined
var num = 6;
console.log(num); // Returns undefined
var num = 6;

函数表达式

函数表达式会有变量提升,在赋值之前,值也是 undefined

js
console.log(fn)
var fn = function (a) {
  return a;
}
// Returns undefined
console.log(fn)
var fn = function (a) {
  return a;
}
// Returns undefined

覆盖

变量赋值会覆盖函数声明

js
fn();
var fn = function () {
  console.log(1);
}
fn();
function fn () {
  console.log(2);
}
var fn = function () {
  console.log(3)
};
fn();
var fn = 4
console.log(fn)
// 2 1 3 4
fn();
var fn = function () {
  console.log(1);
}
fn();
function fn () {
  console.log(2);
}
var fn = function () {
  console.log(3)
};
fn();
var fn = 4
console.log(fn)
// 2 1 3 4

与块级作用域

var i 会变量提升到函数 foo,for 循环是同步代码,for 循环执行完成才会执行异步宏任务 setTimeout

js
function foo() {
  for (var i = 0; i < 10; i++ ) {
    setTimeout(() => {
      console.log(i)
    })
  }
}
foo()
// 10 (10) 打印 10个10
function foo() {
  for (var i = 0; i < 10; i++ ) {
    setTimeout(() => {
      console.log(i)
    })
  }
}
foo()
// 10 (10) 打印 10个10

let i 块级作用域 与最近的{}绑定

js
function foo() {
  for (let i = 0; i < 10; i++ ) {
    setTimeout(() => {
      console.log(i)
    })
  }
}
foo()
// 1,2,3,...,9,10
function foo() {
  for (let i = 0; i < 10; i++ ) {
    setTimeout(() => {
      console.log(i)
    })
  }
}
foo()
// 1,2,3,...,9,10