1. let和const
NOxONE 2/14/2022 ES6
# 1. let
# 1.1 let 声明的变量会创建自己的块级作用域
不多 bb,直接上代码:
{
let a = 10
var b = 1
}
a // ReferenceError: a is not defined.
b // 1
function f1() {
let n = 5
if (true) {
let n = 10
}
console.log(n) // 5
}
function f1() {
let n = 5
if (true) n = 10
console.log(n) // 10
}
for 循环很适合使用 let
var a = []
for (let i = 0; i < 10; i++) {
// let i = 6
a[i] = function () {
console.log(i)
}
}
a[6]() // 6
var a = []
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i)
}
}
a[6]() // 10
分析如下
(PS:不知道AO
、VO
、执行上下文
是什么的同学推荐看看我写的这篇《一文搞懂执行上下文、VO、AO、Scope、[[scope]]、作用域链、闭包》 (opens new window),绝对满满干货,不墨迹)
// let声明的变量可以创建自己的作用域,故i得以保存
letContext = { // 这就是所谓的块级作用域
VO:{
i: 6 // 0
},
Scope:[ VO ]
}
a[6].[[scope]] = letContext.Scope
a[6]Context = { // a[6]函数执行时的上下文
AO:{
arguments:{
length:0
},
},
Scope:[ AO, ...a[6].[[scope]] ] // [AO,{ i:6 }]
}
// 而 var声明的变量无自己的作用域,获取的是全局变量
gContext = {
VO:{
a[0]:function(){console.log(i)},// a[1] ~ a[9]
i: 10
},
Scope:[ VO ]
}
a[6].[[scope]] = gContext.Scope
a[6]Context = {
AO: {
arguments:{
length:0
}
},
Scope:[ AO, ...a[6].[[scope]] ]
// [
// AO,
// {
// a[0]:function(){console.log(i)},// a[1] ~ a[9]
// i: 10
// }]
}
# 1.2 let 不存在变量提升
// var 的情况
console.log(a) // 输出undefined
var a = 2
// let 的情况
console.log(a) // 报错ReferenceError
let a = 2
# 1.3 let 声明的变量会存在暂时性死区
let 声明的变量会绑定当前的作用域,不再受外部的影响,且在当前区域锁死 let 声明之前的变量访问
var a = 7
if (true) {
a = 8 // ReferenceError,这是因为a只能用内部的,外部的不行,然后内部在声明前就访问会报错
let a // 暂时性死区结束
a = 9
alert(a) // 9
}
当然,也有隐形的死区
function fn(x = y, y = 2) {
return [x, y]
}
fn() // 报错,这是因为y未声明就试图用其给x赋值
// 下面这样就不会报错
function fn(x = 2, y = x) {
return [x, y]
}
fn() // [2, 2]
# 1.4 let 不允许重复声明
不多 bb,直接上代码:
// 报错
function fn() {
let a = 10
var a = 1
}
// 报错
function fn() {
let a = 10
let a = 1
}
// 隐形重复声明,通过函数参数
function fn(arg) {
let arg
}
fn() // 报错
function fn(arg) {
{
let arg
}
}
fn() // 不报错,这是因为在arg声明在嵌套的语句块里
# 2. const
const 与 let 类似,只不过更加严格:
- 声明的变量不能改变(常量)
- 声明时必须赋值,不能后面再赋值
在本质上,const 保证的是指针不改变
,但是改变指针所指的对象的属性是可以的喔~
如果要定义一个“常量对象”,那么要使用Object.freeze(obj)
,效果相当于将对象的每个属性 const
const obj = Object.freeze({ name: 'jack' })
那么问题又来了,如果对象的属性又是一个对象咧?我不改它的指针,我可以改它的属性啊!哈哈,那么彻底冻结吧~
function constantize(obj) {
Object.freeze(obj) // 冻死外部
Object.keys(obj).forEach((key) => {
// 排查内部漏网之鱼
if (typeof obj[key] === 'object') {
// 你这个属性是一个对象是吧?老子套娃冻死你!
constantize(obj[key])
}
})
}