var
在`es5`中, 顶层对象的属性和`全局变量`是等价的,用var声明的变量既是全局变量,也是顶层变量:
- 顶层对象,在`浏览器环境`指的是`window对象`,在`node环境`指的是`global对象`。
使用var声明的变量存在变量提升的情况
使用var,能够对一个变量进行多次声明,后面声明的变量会覆盖前面的变量声明:
- 在`函数中`使用var声明变量时,该变量是`局部`的。
var a = 1 // 此处声明的变量a为全局变量
function foo() {
var a = 2 // 此处声明的变量a为函数foo的局部变量
// a = 2 // 此处声明的a是全局变量
console.log(a) // 2
}
foo()
console.log(a) // 1
console.log(a) // undefined
var a = 1
var a
console.log(a) // undefined
a = 1
console.log(b) // 未声明过的变量进行操作,就会报错
let
let是`es6`新增的命令,用来`声明变量`
用法类似于var,但是所声明的变量,`只在let命令所在的代码块内有效,不存在变量提升`:
- 只要块级作用域内存在let命令,这个区域就不再受外部影响。
使用let声明变量前,该变量都不可用,也就是大家常说的暂时性死区:
- let不允许在相同作用域中重复声明
let a = 1
console.log(a) // 1
console.log(b) // Uncaught ReferencenError: b is not defined
let b = 2
function foo() {
let a = 1
let a = 2 // Uncaught SyntaxError: Identifier 'a' has alreadey been declared
}
经典的var和let的for循环例子
for (var i = 0; i < 10; i++) {
console.log(i) // 0 - 9
setTimeout(() => {
console.log(i) // 10 个 10
}, 3000)
}
console.log(i) // 10
for (let i = 0; i < 10; i++) {
console.log(i) // 0 - 9
setTimeout(() => {
console.log(i) // 0 - 9
}, 3000)
}
console.log(i) // Uncaught referenceError: i is not defined
const
const`声明一个只读的常量`,一旦声明,常量的值就不能改变:
- const 一旦声明变量,就必须立即初始化,不能留到以后赋值
- 如果之前var或let声明过此变量,再用const声明同样会报错
const实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不能改动:
- 对于简单类型的数据,值就保存在变量指向的那个内存地址,因此等同于常量
- 对于复杂类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针
- const只能保证这个指针是固定的,并不能确保改变量的结构不变
const PI = 3.1415
PI // 3.1415
PI = 3 // TypeError: Assignment to constant variable.
const 声明的变量不能改变只,这意味着,const一旦生命变量,就必须立即初始化,不能留到以后赋值。
const foo = {}
// 为foo添加一个属性
foo.prop = 123
foo.prop // 123
foo = {} // 将foo指向另一个对象,就会报错。TypeError: 'foo' is read-only
常量foo储存的是一个地址,这个地址指向一个度夏宁。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性
// 如果真的想将对象冻结,应该使用Object.freeze方法
const foo = Object.freeze({})
//常规模式时,下面一行不起作用
// 严格模式时, 该行会报错
foo.prop = 123
// 彻底冻结对象 (用递归函数)
const constantize = (obj) => {
Object.freeze(obj)
Object.keys(obj).forEach((key, i) => {
if (typeof obj[key] === 'object') {
constantize(obj[key])
}
})
}
变量提升
- var 声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
- let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
暂时性死区
- var不存在暂时性死区
- let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
块级作用域
重复声明
- var允许重复声明变量
- let和const在同一作用域不允许重复声明变量
修改声明的变量
- var和let可以
- const声明的是一个只读的常量。一旦声明,常量的值就不能改变。
使用
- 能使用const的情况尽量使用const,其他情况下大多数使用let,避免使用var