好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ES6+ const

ES6+ const

1. 前言

上一节 我们学习了使用 let 取代 var 声明变量,但是很多情况下,我们希望我们声明的变量不能被 修改 。在 ES5 中不能直接声明 一个 常量,如果想声明 一个 不可 修改 的变量需要借助 defineProperty 方法 。ES6 为了弥补这方面的缺失,新增了 const 语句用于声明 一个 常量。本节我们还将学习到 let 、 const 、 var 的区别。

2. 语句使用

2.1 基本使用

const 的使用类似于 let ,不同的是 const 在声明时必须初始化 一个 值,而且这个值不能被改变。

  const  PI  =   ;    // 定义 一个 圆周率常量 PI 
 

上面的 代码 声明了 一个 常量 PI,如果声明时没有初始化值时,则会抛出异常。

  const  PI ; 
 // Uncaught  Syntax Error: Missing initializer in const decl ara tion 
 

const 语句声明的是 一个 常量,并且这个常量是不能被更改的:

  const  PI  =   ;    // 定义 一个 圆周率常量 PI 
PI  =                // Uncaught TypeError: Assignment to constant variable. 
 

这里声明了 一个 圆周率常量,我们知道圆周率是固定的不会被改变的,如果对 PI 重新赋值,则会抛出不能给常量分配变量的 错误 。

但如果使用 const 声明的变量是 一个 对象类型的话,我们可以改变对象里的值,这是因为 const 存的变量只是 一个 地址的引用,所以只要不改变引用的值,就不会报错。如下面的例子:

  const  obj  =   {  }  ; 
obj . a  =             // 12 
 const  arr  =   [  ]  ; 
arr .  push  (  )  ;         // 12 
arr  =   {  }  ;             // Uncaught TypeError: Assignment to constant variable. 
 

使用 const 声明了 一个 对象和 一个 数组,然后 增加 对象的 属性 和 增加 数组的值都不会报错,这是因为我们没有改变 obj 和 arr 的引用。如果对 arr 进行重赋值,则会报不能给常量分配变量的 错误 。

2.2 const 和 let 共有特性

由于 const 和 let 都是声明变量使用的,所以他们的使用 方法 基本相同,下面总结一下它们共有的 内容 ,详情参考 上一节 的 let 的使用:

不能进行变量提升,在声明前不能被使用,否则会抛出异常; 存在暂时性死区,在块中不能被重复声明。

3. ES5 模拟实现 const

在 ES6 之前是不能 定义常量 的,如果想 定义常量 的话,需要借助 ES5 中的 defineProperty 方法 ,这里我们写个示例:

  function   setConst  ( key ,  value ,  obj )   { 
  Object .  defineProperty  ( window ,  key ,   { 
     get  :   function  (  )  { 
       return  value ; 
     }  , 
     set  :   function  (  )  { 
      console .  error  (  'Uncaught TypeError: Assignment to constant variable'  )  ; 
     }  , 
   }  )  ; 
 } 
 setConst  (  'PI'  ,   )  ; 
console .  log  ( PI )       // 3.1415 
PI  =   ;               // Uncaught TypeError: Assignment to constant variable. 
 

上面的 代码 是 一个 定义常量 的 函数 ,使用了 ES5 的 Object.defineProperty 方法 ,这个 方法 允许在 一个 对象上定义 一个 新的 属性 ,具体使用详情可以参考 ES5 的相关文档说明。这里我们会在 window 对象上 添加 属性 ,也可以自己定义 一个 对象进行 添加 ,可以实现局部作用域的 效果 。通过向 setConst 方法 中传入指定的变量和值来声明 一个 常量,这样我们就在 ES5 中实现了常量的概念。由此可见,ES6 的 const 带来的好处。

4. 场景实例

4.1 let 及 const 常见问题

在工作中经常会遇到 var 、 let 及 const 以下几个问题:

什么是变量提升? 什么是暂时性死区? var 、 let 及 const 区别?

这些问题在上面的讲解中都有提到过,这里我们总结一下:

4.2 什么是变量提升?

变量还没有被声明,但是我们却可以使用这个未被声明的变量,这种情况就叫做提升,并且提升的是声明。

 console .  log  ( a )  ;   // undefined 
 var  a  =  
 

这个 代码 其实可以写出下面这样的方式:

  var  a ; 
console .  log  ( a )  ;    // undefined 
a  =  
 

其实变量提升就是,把变量名统一地提升到作用域的顶部进行率先定义,这也就是变量提升。不仅变量可以被提升, 函数 也可以被提升,并且 函数 的提升要优于变量的提升, 函数 提升会把整个 函数 挪到作用域顶部。

4.3 什么是暂时性死区?

暂时性死区主要是针对 let 和 const 而言的,因为它们不存在变量提升,所以在它们声明变量之前是不能使用的,这个时候如果使用了就会报错,这时候就形成了暂时性的死区,也就是不能被引用。

  { 
  console .  log  ( name )  ;    // ReferenceError: name is not defined.  
   let  num  =   ; 
 } 
 

定义前被引用则会抛出异常。

4.4 var、let 及 const 区别?

上面两个 问题解决 了,再看它们的区别其实就是显而易见的,主要从以下几个方面来分析它们之 间的 区别:

var 声明的变量是全局作用域下的,会污染 全局变量 ;let、const 可以和 {} 连用,产生块作用域不会污染全局; var 存在提升,我们能在声明之前使用。let、const 因为暂时性死区的原因,不能在声明前使用; var 在同一作用域下,可以重复声明变量;let、const 不能重复声明变量,否则会报错; let 和 const 的 用法 基本一致,但是 const 声明的变量不能再次赋值。

4.5 实例

下面的实例主要考察作用域的问题,下面的 代码 输出 的结果是什么?

  for   (  var  i  =   ;  i  <   ;  i ++  )   { 
   setTimeout  (  (  )   =>   { 
    console .  log  ( i )  ; 
   }  ,   * i )  ; 
 } 
 // 3 
 // 3 
 // 3 
 

代码 分析: 这里由于 setTimeout 是异步回调 函数 ,所以 for 循环运行完后才会执行 setTimeout 内的 调用 栈。使用 var 声明的变量是全局作用域的,循环完后 i 的值是 3,所以会间隔 1s 打印 一个 3。想要 i 的值不被覆盖,这时可以借助 let 的块级作用域的特性,来 解决 这个问题:

  for   (  let  i  =   ;  i  <   ;  i ++  )   { 
   setTimeout  (  (  )   =>   { 
    console .  log  ( i )  ; 
   }  ,    *  i )  ; 
 } 
 // 0 
 // 1 
 // 2 
 

代码 分析: 这里循环的变量 i 是 let 声明的,当前的 i 只在本轮循环有效,所以每一次循环的 i 其实都是 一个 新的变量。你可能会问,如果每一轮循环的变量 i 都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为在 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量 i 时,就在上一轮循环的基础上进行计算。

另外,for 循环还有 一个 特别之处,就是设置循环变量的那部分是 一个 父作用域,而循环体内部是 一个 单独的子作用域。这样每次定义的 i 都是局部作用域下的变量,所以在异步之后,i 的值是不会变的,所以依次打印 0 到 3 的结果。

5. 小结

本节我们学习了使用 const 来声明 一个 常量,这里需要注意以下几点:

对于不可变的变量,尽可能地使用 const 来声明变量,如果需要更改值的时候再用 let 声明; let 和 const 都只作用于块级作用域内; let 和 const 声明的变量,都不能变量提升,都存在暂存死区; let 和 const 声明的变量不允许重复声明,无论重复用 var 或者其他声明都不行。

查看更多关于ES6+ const的详细内容...

  阅读:59次

上一篇

下一篇

第1节:ES6+ 简介    第2节:ES6 环境配置    第3节:ES6+ let    第4节:ES6+ const    第5节:ES6+ 展开语法    第6节:ES6+ 剩余参数    第7节:ES6+ 解构赋值    第8节:ES6+ 模版字符串    第9节:ES6+ 箭头函数    第10节:ES6+ 数值扩展    第11节:ES6+ isFinite()&isNaN()    第12节:ES6+ Number 对象的方法    第13节:ES6+ Math 对象的扩展    第14节:ES6+ includes()    第15节:ES6+ 字符串的扩展    第16节:ES6+ startsWith()    第17节:ES6+ endsWith()    第18节:ES6+ repeat()    第19节:ES6+ padStart()    第20节:ES6+ padEnd()    第21节:ES6+ trim()    第22节:ES6+ Array.from()    第23节:ES6+ of()    第24节:ES6+ find()和findIndex()    第25节:ES6+ copyWithin()    第26节:ES6+ fill()    第27节:ES6+ isArray()    第28节:ES6+ 对象的扩展    第29节:ES6+ flat()    第30节:ES6+ 可选链操作符    第31节:ES6+ Object.is()    第32节:ES6+ Object.assign()    第33节:ES6+ Object.keys()    第34节:ES6+ Object.values()    第35节:ES6+ Object.entries()    第36节:ES6+ 数据结构扩展    第37节:ES6+ Set    第38节:ES6+ WeakSet    第39节:ES6+ Map    第40节:ES6+ WeakMap    第41节:ES6+ Symbol    第42节:ES6+ for...of    第43节:ES6+ 迭代协议    第44节:ES6+ 实现一个简版的 Promise    第45节:ES6+ Promise 基础    第46节:ES6+ Promise 进阶    第47节:ES6+ Generator 基础    第48节:ES6+ Generator 函数应用    第49节:ES6+ async/await    第50节:ES6+ Class 前置知识    第51节:ES6+ Class    第52节:ES6+ Proxy    第53节:ES6+ Reflect(一)    第54节:ES6+ Reflect(二)    第55节:ES6+ 模块化(一)    第56节:ES6+ 模块化(二)    第57节:ES6实战1-实现Vue3 reactive 源码    第58节:ES6实战2-实现 Vue3 effect 源码    第59节:ES6 实战2-封装请求    第60节:ES6+ 实战3-代码整洁之道    第61节:ES6 Map原理分析    第62节:ES6module语法加载importexport    第63节:ES6的循环与可迭代对象示例详解