当前位置:网站首页>let const

let const

2022-07-07 05:56:00 lazytomato

start

  • 我又来学习ES6了。
  • 因为我发现我在使用某些ES6的 API的时候,总觉得差点意思。
  • 花点时间,结合思维导图的形式,系统性的过一遍。
  • ღ( ´・ᴗ・` )比心

思维导图:
在这里插入图片描述

1. let 和 const 有哪些特点(相同点)

1.1 不会变量提升

console.log(lazy) // undefined
var lazy= '偷懒'


console.log(tomato) // tomato is not defined
let tomato= '你好呀'

讨论

var a = 1
function s() {
    
  console.log(a)
  let a = 2
  // 如果不写 `let a = 2` 上面的console.log(a) 会打印 1

  // 但是写了 `let a = 2` Cannot access 'a' before initialization
}
s()

如何解释上面的代码

  • 变量提升只是一种语法定义。

  • 其实实质就是一段代码在上下文创建阶段(也就是编译阶段)是能够识别到 var 和 let 创建的变量的

  • 只会对二者的操作不一样:对 var 定义的变量初始化为 undefined,而 let 定义的变量仍然处于未初始化状态。

1.2 重复声明报错

代码

var a = '1'
console.log(a)
var a = '2'
console.log(a)

let b = '1'
console.log(b)
let b = '2'  // Uncaught SyntaxError:Identifier 'b' has already been declared 翻译一下:未命名 语法错误: 标识符“b”已声明
console.log(b)

思考

  • 使用 let 去声明两次同一个名称的变量,直接报错了,整体代码都不运行了。(运行效果可以看后续截图)
  • 分开运行上下两块代码,var 是支持重复声明的。

运行截图
在这里插入图片描述

1.3 不绑定全局作用域

代码

var a = '1'

let b = '2'

console.log(window.a)  // 1
console.log(window.b)  // undefined

解释

顶层对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。这样的设计带来了几个很大的问题,首先是没法在编译时就报出变量未声明的错误,只有运行时才能知道(因为全局变量可能是顶层对象的属性创造的,而属性的创造是动态的);其次,程序员很容易不知不觉地就创建了全局变量(比如打字出错);最后,顶层对象的属性是到处可以读写的,这非常不利于模块化编程。另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的。

ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩

-内容来自 ECMAScript 6 入门教程_阮一峰

个人思考

对于我自己来说,这个地方是一个很模糊的点。了解到 顶层对象的属性与全局变量挂钩 的缺点后,这样做的原因还是很好理解的。

小记一下: let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性

1.4 暂时性死区

代码

var tmp = 123;

if (true) {
    
  tmp = 'abc'; // ReferenceError: Cannot access 'tmp' before initialization 翻译一下 引用错误: 在初始化之前无法访问 'tmp‘ 
  let tmp;
}

思考

  • 只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

  • 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

1.5 块级作用域

先看代码

代码1

if (false) {
    
  var a = 1
}

console.log(a) // undefined

console.log(b) // ReferenceError: b is not defined

代码2

let a = 1
{
    
  let b = 2
}

console.log(a) // 1
console.log(b) // ReferenceError: b is not defined

思考

  1. ES5 只有全局作用域和函数作用域,没有块级作用域。这就会导致 代码1 中的var a 会被提升到顶部。
  2. 而 let const 声明的是存在块级作用域的,在外部是无法读取的。

块级作用域

MND的官方说明:块作用域

任何一对花括号 {} 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

总结

  1. ES5 只有全局作用域和函数作用域,没有块级作用域。
  2. ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。

我理解到的是,ES6中主要注意 if 和 trycatch 的大括号,会有块级作用域。

2. 不同点

const声明的变量指向的那个内存地址所保存的数据不得改动。

推荐使用const声明变量,确保变量内存地址不变,可以减少bug的发生。

3. 扩展

3.1 函数能不能在块级作用域声明?

例如在 if , trycatch中声明函数。

  1. ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。

  2. 但是!! 浏览器没有遵守这个规定 还是支持在块级作用域之中声明函数。

  3. ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

  4. 如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式

    • 允许在块级作用域内声明函数。
    • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
    • 同时,函数声明还会提升到所在的块级作用域的头部。

    注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

看的稍微有点绕,我多读了几遍,写一写自己的理解。

  1. ES5中是不允许块级作用域声明函数的,但是浏览器中是支持的。

  2. ES6中明确允许的块级作用域可以声明函数,但是在块级作用域中,函数声明语句类似 let。外部不可引用。

  3. 为了减少 ES6 的改动对 ES5的影响,对浏览器的实现,可以不按照 ES6规定实现,按如下规定实现:

    • 允许在块级作用域内声明函数。

    • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。

    • 同时,函数声明还会提升到所在的块级作用域的头部。

      #以上三条仅针对 ES6的浏览器 实现有效。

3.2 顶层对象

  1. 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。

  2. 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。

  3. Node 里面,顶层对象是global,但其他环境都不支持。

3.3 ES6 声明变量的六种方法

  • ES5 只有两种声明变量的方法:var命令和function命令。

  • ES6 除了添加letconst命令,还有两种声明变量的方法:import命令和class命令。

    所以,ES6 一共有 6 种声明变量的方法。

end

  • 其实这是我第三次学这个 let 和 const 了,可能不是最后一次。

  • 当然这次也是很有收获,例如:

    • 块级作用域;

    • 函数在块级作用域的声明;

    • let const 到底会不会变量提升;

  • 其次 let const 的新特性,都是用来解决以前的痛点和问题点,知道原因再看结果就很通透了。

  • 编写于2022/07/06-23/10

原网站

版权声明
本文为[lazytomato]所创,转载请带上原文链接,感谢
https://blog.csdn.net/wswq2505655377/article/details/125630659