用 const 仍是用 let?

ES6 里新增了两种声明变量的方式,let 和 const,加上原来的 var,一共就有三种方式来声明变量了。那到底该用哪一个呢?关于“尽量不用 var” 这一点,你们应该没有什么意见分歧(其实仍是有少数人不这么想的),关于“是用 let 仍是用 const”,社区里主要有两种不一样的观点:html

1. 默认全用 let,只在符合一些写代码的人的主观判断条件的时候用 const,下面举个这样的“主观判断条件”的例子(实际代码中用到 const 的概率大概会是 0.1%):数组

  • 你能 100% 肯定该变量永远不会在其它的代码行里被从新赋值,可是该变量的初始值有可能在将来会被调整(有点配置项的意思),且
  • 该变量的初始值是个数字字面量(或者多个数字组成的数学运算表达式)、字符串字面量、布尔字面量、数组字面量、对象字面量、正则字面量、symbol "字面量"(打引号是由于 symbol 其实没有字面量),且
  • 该变量是个全局变量,或者是模块内的全局变量

代码举例:函数

const VERSION = 2
const TIMEOUT = 10000

const MB = 1024 * 1024
const DAY = 24 * 60 * 60 * 1000

const COLOR = "rgb(255,255,255)"
const HTMLNS = "http://www.w3.org/1999/xhtml"

const BUTTONS = ["left", "middle", "right"]
const SIDES = ["left", "right", "top", "bottom"]

2. 默认全用 const,只有该变量须要被从新赋值才用 let (实际代码中用到 const 的概率大概会是 95%),和上面举的三个主观判断条件对比一下差别:工具

  • 不能 100% 肯定该变量永远不会被从新赋值(可能只是如今是没被从新赋值,说不定将来会),或者
  • 该变量的初始值不是字面量,好比说是个函数调用表达式,或者
  • 该变量是个局部变量

第一种用法是很是主观的,好比你用 const 的判断条件有可能就和我上面举的不同,好比你也许以为局部变量也能够用 const ?或者你觉的数组和对象是可变的值,怎么能用 const 呢?由于很主观,因此一个团队的代码风格很难达成一致,甚至只有你一我的维护的代码,const 的用法在不一样的时间内也没有统一的规律,由于可能连你本身都没有明确的想过:“何时我应该用 const”,说白了就是“看心情”。而第二种用法是很是客观的,简单直接,没有含糊不清的地方,若是采用这种用法,至少团队代码风格的统一是不成问题的。测试

ES6 以前你有没有写过或者见过相似下面这样的代码:ui

var ids = document.getElementById("ids").value // 多个 id 组成的字符串,好比 "100 101 102"
ids = ids.split(" ") // 拆分红数组
ids.forEach(...

ids 这个变量的类型从字符串变成了数组,但变量名却没变(写代码的人懒的想新名字),这被认为是一种很差的编码风格。若是有“默认都用 const”的风格约定(第一行已经写了 const ids),会迫使写代码的人在第二行想一个新的变量名(固然他也有可能把一行的 const 改为 let),而默认用 let 的风格不会让人有种迫使感(固然用 let 的人也可能根本不须要迫使感就会主动想一个新的名字,看人)。this

除了上面说的这两个“默认用 const” 的优势,还有人说默认用 const 比用 let 能让代码更有可读性,更语义:读代码的人看一个变量的声明方式就知道它在下面会不会被从新赋值。但这些都是从代码风格上说事的,代码风格是很主观的一个东西,有人觉的好,有人并不觉的很差,你很难拿着这样的优势去说服默认用 let 的人。好比他们可能会回击说:“咱们团队有详细的风格指南,规定了何时用 const,代码风格统一不是问题”(第一个优势没了);“一样是有风格指南,咱们团队的人不会复用不应复用的变量名”(第二个优势没了);“let 比 const 短”(你反而无言以对,被击败)。编码

有没有更有说服力的优势呢,好比能不能举个“默认用 const 可以避免,而默认用 let 避免不了的 bug” 的代码实例呢?下面我构思了一个:设计

let path = require("path") // 这里 path 是个全局变量 
/*
  这里有不少代码
*/
function bar() {
  let path = "." // 这里 foo 是个局部变量
  /*
    这里有不少代码
  */
  if (this.isInProduction) { // 只在生产环境中执行的代码
    path = "~" // 为局部变量 path 从新赋值
  }
  /*
    使用局部变量 path 的代码
  */
} 

假设这是一段运行正常的代码, path 是个全局变量,同时又是个 bar 函数的局部变量。某天有人重构 bar 函数的时候认为 path 这个局部变量起的很差,和全局变量冲突了,应该换了个名字,而后把 bar 函数里面声明 path 的地方和使用 path 的地方的 path 都替换成了 filePath,但不当心漏掉了 path = "~" 这一行里的 path,本地测试没问题,上线出了故障,好心办了坏事啊。eslint

若是这个全局变量 path 是用 const 定义的话。。。也并不能发现这个 bug。为何呢,请看个人上篇文章,是由于关于 const,ES6 有个设计缺陷,就是为 const 变量从新赋值不是个静态错误。可是若是你同时使用了 ESLint 并开启了 no-const-assign 规则,这个线上问题就能被扼杀在萌芽状态:

总结:默认用 const 能够带来一些代码风格上的好处,若是配合 Lint 工具还能够避免某些意外的 bug,但若是不使用 Lint 工具,相反可能会形成一些意外的 bug(好比上篇文章中开头举的)。不论是可能形成的 bug,仍是可能避免的 bug,都是些 edge case,并不常见,因此很大程度上,选择默认用 const 仍是 let 还是一件很主观的事。

ES6 的编辑 Allen Wirfs-Brock 曾说过,若是能重来一次,他但愿把 let 设计成像如今的 const 同样,而新增一个好比 let var 代替如今的 let。但由于 const 这个保留字在 JS 刚发明的时候就从 Java 抄过来了,let/const 这对儿关键字在制定 ES5 的时候就计划在 ES6 里用了,因此 ES6 里也就没再改了。

相关文章
相关标签/搜索