Skip to content

这一章主要记录变量声明相关的内容。

目前存在的变量声明方式总共有6种:

  1. var
  2. function
  3. let
  4. const
  5. class
  6. import

其中,varfunctionEs5 版本中就已经存在的。

1-1.变量提升

利用 varfunction 的声明方式,会存在变量提升的效果。而且 function 的优先级高于 var。譬如:

js
// 这里存在变量提升,但不会打印 undefined。而是打印函数foo。
console.log(foo)
var foo = 'var-foo'
function foo() {
  console.log('function-foo')
}

TIP

变量提升,会提升到文件顶部或者函数作用域顶部。

使用 letconst 的声明,并不会存在变量提升。在变量声明之前,使用该变量,会存在临时性死区

js
// 临时性死区
console.log(temp)
let temp = 123

另外 letconst 两者的共同点是都不能重复声明,区别在于const声明的是常量。不能改变变量地址。

js
let a
let a = 123 // Uncaught SyntaxError: Identifier 'a' has already been declared
js
const obj = {}
obj.id = 19 // works 因为这里并不改变变量的引用地址

obj = { id: 19 } // Uncaught TypeError: Assignment to constant variable.

1-2.块级作用域

Es5 中并不存在块级作用域,存在函数作用域

js
{
  var a = 'hello'
}
console.log(a) // 'hello'

而在 Es6 中存在块级作用域函数作用域

js
{
  var a = 'hello'
  let b = 'world'
}
console.log(a) // hello
console.log(b) // Uncaught ReferenceError: b is not defined

TIP

letconst 会使得声明的变量存在块级作用域。

最后这里记录一道比较基础的面试题。

js
for (var i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(i)
  })
}
// 打印 5 个 5 而不是 0 1 2 3 4

解决办法有两个:

js
// ①利用闭包
for (var i = 0; i < 5; i++) {
  setTimeout(((j) => {
    return () => {
      console.log(j)
    }
  })(i))
}

// ②利用 let
for (let i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(i)
  })
}

1-3.不污染全局变量

利用 var 创建的变量默认会挂载到全局作用域下:

js
var a = 'hello world'
console.log(window.a) // 'hello world'
console.log('a' in window) // true

而利用 let 或者 const 则不会污染全局作用域:

js
const b = 'hello world'
console.log(window.b)
console.log('b' in window)