1. let和const

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:不知道AOVO执行上下文是什么的同学推荐看看我写的这篇《一文搞懂执行上下文、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])
		}
	})
}
    人生如梦,
    我投入了的却是真情,
    世界先爱了我,
    我不能不爱它。
    红莲华
    x
    loading...