0
点赞
收藏
分享

微信扫一扫

es6 中let 与 const 的应用

RockYoungTalk 2021-09-24 阅读 91

let

基本用法

ES6 新增了let命令,用于声明变量,它的用法类似var,但是let 只在它所在的代码块内起作用;

那么什么是代码块呢?

代码块

代码块就是大括号{}所写的语句,在{}里面可以写多条语句,一个{}就是一个代码块;
{var a = 6; a++}
// 返回6
在ES5中,代码块只起到一个语句分组的作用,里面的代码对外面来说都是可见的;
{ var a = 6; a = a + 4;}
console.log(a)
// 返回10
但是到了ES6,由于增加了let命令,使得代码块里面的内容对于外面来说并非全部可见,也就成就了块级作用域;如下例,在一个代码块里面使用let定义了d变量,但是在外面是访问不到d;

注意的是代码块后面不需要加分号,当然加了也不会报错;
{ var a = 6; a = a+4;}
// 返回10

ES6中,let 为 js 新增了块级作用域;

在ES5只有全局作用域和函数作用域,没有块级作用域这个概念,就如大家所知道的,就会导致了很多不合理的情况发生;比如下面的例子:

这个例子本来想得到外层的aa的值,但是由于变量提升,而读到的是内层aa的undefined;

如上,把var 替换成let,就一切符合我们的逻辑了;
ES6允许块级作用域的任意嵌套

{{{ let name = 'alice' }}}

外层作用域无法读取内层作用域的变量;

内层作用域可以访问外层作用域的变量;

的立即执行匿名函数(IIFE)不再必要了;

另外,考虑到环境导致的行为差异很大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式的形式,而不是函数声明语句;

现在我们再回到let的基本用法

let 特点 之一:只在其所在代码块里面有效

上面说了let所声明的变量只在所在的代码块内有效;像我们常用的for循环就特别适合使用let命令;如下例子:

上面的代码,变量i是let声明的,当前的i只在本轮有效,所以每一次循环的i其实都是一个新的变量,于是最后输出的是6。大家可能会问,如果每一轮循环的变量i都是重新声明的,那它是怎么知道上一轮循环的值从而计算出本轮的值呢?这是因为js引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上计算。
另外,for循环还有一个特别的地方,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

let 特点之二:不存在变量提升

我们之前使用的var命令会发生“变量提升”,即变量可以在声明之前使用,值为undefined.这种现象多少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则便会报错。


在以上代码中,变量aa用var命令声明会发生变量提升,即脚本开始运行时,变量aa已经存在了,但是没有值,所以会输出undefined。变量bb用let命令声明则不会发生变量提升。这表示声明它之前,变量ba是不存在的,这时如果用到它,就会抛出一个错误。

let 特点之三:暂时性死区

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

上面的例子报错,因为在let声明变量tt之前,调用了tt,按照es6的let的暂时性死区特性,tt不可用,所以会报错;

ES6规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在ES5中是很常见的,现在有了这种规,避免此类错误就很容易了。

let特点之四:不允许重复声明

let不允许在相同作用域内重复声明同一个变量;

const命令

基本用法

  • const声明一个只读的常量,一旦声明,常量的值就不能改变,这意味着一旦声明常量,就必须立即初始化,不能留到以后赋值。
  • 只在所在的块级作用域内有效
  • const命令声明的常量也不会提升,同样存在暂时性死区,只能在声明后使用。

本质

  • const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值)而言,值就保存在变量指向的内存地址中,因此等同于常量。但对于复合类型的数据(主要是对象和数组)而言,变量指向的内存地址保存的只是一个指针,const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,这完全不能控制。


上述的代码中,常量foo存储的是一个地址,这个地址指向一个对象。不可变的只是这个地址,既不能把foo指向另一个地址,但是对象本身是可变的,所以依然可以为其添加新属性;

  • 如果真的想将对象冻结,应该使用Object.freeze({});


上述代码中,由于使用了Object.freeze({}),使得freezeObj.prop = 123;这行代码没有执行,这是在普通模式下,如果实在严格模式下,执行到这行代码会报错;

举报

相关推荐

0 条评论