js 变量提升(hoisting)

2019-07-30  本文已影响0人  Johnson23

先了解一下变量的生命周期

变量声明提升

var a = 1
function test() {
  console.log(a)
  var a = 1
}
test()

根据变量声明提升和变量搜索机制,函数test应为

function test(){
  var a = undefined // 变量声明提升了,并初始化为undefined
  console.log(a)  // undefined
  a = 1 // 变量赋值
}

再来看看下面这个例子:

c = 5
function test2() {
    window.c = 3
    console.log(c)
    var c = 1
    console.log(window.c)
}
test3()

根据变量声明提升和变量搜索机制,函数test2应为

function test2() {
  var c = undefined // 局部变量c声明提升,并初始化为undefined
  window.c = 3
  console.log(c) // 此c为局部变量,undefined
  c = 1
  console.log(window.c) // 3
}

再来测试下const:

const d = 3
if(true) {
  console.log(d) // // Uncaught ReferenceError: x is not defined
  const d = 1
}

一开始我认为let和const也存在声明提升,看了知乎的这篇文章——我用了两个月的时间才理解 let之后改变了我的看法。以下摘自这篇文章的一部分。

首先明确一点:提升不是一个技术名词。

要搞清楚提升的本质,需要理解 JS 变量的「创建create、初始化initialize 和赋值assign」

有的地方把创建说成是声明(declare),为了将这个概念与变量声明区别开,我故意不使用声明这个字眼。

有的地方把初始化叫做绑定(binding),但我感觉这个词不如初始化形象。

我们来看看 var 声明的「创建、初始化和赋值」过程
假设有如下代码:

function fn(){
  var x = 1
  var y = 2
}
fn()

在执行 fn 时,会有以下过程(不完全):

也就是说 var 声明会在代码执行之前就将「创建变量,并将其初始化为 undefined」。

这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined。

接下来来看 function 声明的「创建、初始化和赋值」过程
假设代码如下:

fn2()

function fn2(){
  console.log(2)
}

JS 引擎会有一下过程:

也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。

接下来看 let 声明的「创建、初始化和赋值」过程
假设代码如下:

{
  let x = 1
  x = 2
}

我们只看 {} 里面的过程:

这就解释了为什么在 let x 之前使用 x 会报错:

let x = 'global'
{
  console.log(x) // Uncaught ReferenceError: x is not defined
  let x = 1
}

原因有两个

看到这里,你应该明白了 let 到底有没有提升:

最后看 const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。

上一篇 下一篇

猜你喜欢

热点阅读