skip to content

JavaScript
JavaScript 变量提升机制

原则

变量提升分为两种:

  1. 使用 var 声明的变量,比如 var a = 10
  2. 使用 function 声明的函数,比如 function foo() {}

有几点需要注意以下:

  1. 使用 var 声明的变量要比使用 function 声明的函数 优先提升
  2. 全局变量不会得到提升,比如 a = 10 这种

Have A Try

下面祭出 3 道题:

题目 1

function foo() {
  console.log(1)
}
foo()
function foo() {
  console.log(2)
}
foo()
答案与解析
答案 : 2 2 解析 : 两个 foo 函数都被提升, 但是第二个 foo 函数会把 第一个 foo 函数覆盖, 所以两次对于 foo 函数的调用结果都是 2

题目 2

var foo = function () {
  console.log(1)
}
foo()
function foo() {
  console.log(2)
}
foo()
答案与解析
答案 : 1 1
解析 : 
  通过 var 声明的变量 和 通过 function 声明的函数都会得到提升
  但是前者的优先级要比后者高会先被提升
  以此题为例,以下为提升后的代码
  var foo
  function foo() {
    console.log(2)
  }
  foo = function () {
    console.log(1)
  }
  foo() // 1
  foo() // 1

题目 3

function fn() {
  console.log(typeof foo)
  var foo = 'this is variable'
  function foo() {
    return 'this is function'
  }
  console.log(typeof foo)
}
fn()
答案与解析
答案 : function string
解析 :
  以下为提升后的代码
  var foo = undefined         // 变量 foo 先被提升
  function foo() {            // 函数 foo 后被提升,并把变量 foo 覆盖
    return 'this is function'
  }
  console.log(typeof foo)     // function
  foo = 'this is variable'    // 给 foo 重新赋值
  console.log(typeof foo)     // string

题目 4

function foo(a, b) {
  console.log(a, b)
  var b = 3
  function b() {}
  var a = function () {}
  console.log(a, b)
}

foo(1, 2)
答案与解析
答案 : 
  1 [Function: b]
  [Function: a] 3
解析 :
  遇到此题你会发现之前的规则并不适用了
  所以需要使用执行上下文中的 VO 去解释
  当 foo 函数被调用的时候
  VO 首先会找到行参和 arugments,即
  VO = {
    arguments,
    a: 1,
    b: 2
  }
  然后 VO 会找 var 声明的变量并设置为 undefined
  但是这里有个例外是 var 声明的变量如果和形参产生冲突,那么直接忽略
  所以此时 VO 不变,还是
  VO = {
    arguments,
    a: 1,
    b: 2
  }
  紧接着 VO 会去找到字面量 function 声明的函数
  这里如果与行参产生冲突则直接覆盖行参,所以此时 VO 为
  VO = {
    arguments,
    a: 1,
    b: function(){}
  }
  到这里第一个 console.log 的值就显而易见了 1 [Function: b]
  接下来 b 和 a 分别被赋值,那么此时 VO 是
  VO = {
    arguments,
    a: function,
    b: 3
  }
  到这里第二个 console.log 的值也就呼之欲出了 [Function: a] 3