这一章主要记录变量声明相关的内容。
目前存在的变量声明方式总共有6种:
var
function
let
const
class
import
其中,var
与 function
是 Es5
版本中就已经存在的。
1-1.变量提升
利用 var
和 function
的声明方式,会存在变量提升的效果。而且 function
的优先级高于 var
。譬如:
js
// 这里存在变量提升,但不会打印 undefined。而是打印函数foo。
console.log(foo)
var foo = 'var-foo'
function foo() {
console.log('function-foo')
}
TIP
变量提升,会提升到文件顶部或者函数作用域顶部。
使用 let
与 const
的声明,并不会存在变量提升。在变量声明之前,使用该变量,会存在临时性死区。
js
// 临时性死区
console.log(temp)
let temp = 123
另外 let
与 const
两者的共同点是都不能重复声明,区别在于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
let
、const
会使得声明的变量存在块级作用域。
最后这里记录一道比较基础的面试题。
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)