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...