用const还是用let?

紫云飞 紫云飞     2022-08-12     659

关键词:

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

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 之前你有没有写过或者见过类似下面这样的代码:

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

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

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

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

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

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

如果这个全局变量 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 里也就没再改了。

 

es6中的let和const(代码片段)

let和const是ES6新增的几种变量声明方式中的两种,本篇就来谈谈这两种声明方式有什么特点。一、let、const和var的区别let和const的使用方式和var没有区别。但是用let和const声明出的变量,使用规则有所不同,let和const多了一些对变... 查看详情

关于变量声明的var,let,const

...进行重复声明,浏览器并不会报错;    但是用let和const声明变量的话,在同一个作用域内是 查看详情

let和const区别,详细版本(代码片段)

let:声明的是变量1、不存在变量提升//var的情况console.log(foo);//输出undefinedvarfoo=2;//let的情况console.log(bar);//报错ReferenceErrorletbar=2;上面代码中,变量foo用var声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有... 查看详情

对象或数组的首选声明约定是啥:const 还是 let?

】对象或数组的首选声明约定是啥:const还是let?【英文标题】:Whatisthepreferreddeclarationconventionforobjectsorarrays:constorlet?对象或数组的首选声明约定是什么:const还是let?【发布时间】:2018-03-1503:37:04【问题描述】:我不是在问技... 查看详情

let和const(代码片段)

基本概念let命令:用来声明一个变量,同var非常相似const命令:用来声明一个常量,常量就是不可改变的量let命令用let声明变量的注意事项1、使用let声明的变量,所声明的变量只在命令所在的代码块内有效leta=1;varb=2;console.log(a);c... 查看详情

varlet与const

...在同一作用域不能用let重复定义已经存在的标识符。 const与let 查看详情

es6学习笔记之变量声明let,const

最近用淘宝的weex做了个项目,最近稍微闲下来了。正好很久没有接触RN了,所以趁这个机会系统的学习一下ES6的相关知识。孔子说:没有对比就没有伤害。所以我们要拿ES6和ES5好好对比的学习。这样才能明白es6是多少的好,积极... 查看详情

[es6系列-04]再也不乱“哇”了:用let与const替代var(代码片段)

【原创】码路工人Coder-Power大家好,这里是码路工人有力量,我是码路工人,你们是力量。github-pages博客园cnblogs今天的内容是,关于JavaScript中定义变量的变化(其实不确切,函数,常量表示被冷落)。首先,回顾下var定义存在... 查看详情

es6深入浅出-1新版变量声明:let和const-2.视频let和const

以前的var方式声明不好用a=1回声明一个全局变量,输出了1说明a=1确实声明了一个全局变量。但是你把放在其他的地方,就不是声明全局变量了。如果外面有个全局变量a那么函数里面就是给a赋值有两层函数的时候,直接使用的是... 查看详情

浅谈var,let,const(代码片段)

...之前使用,而到了ES6之后官方就不推荐使用了,究其原因还是因为它自身的原因,导致代码令人感觉不太合理。console.log(num);varnum=10;//打印undefined,而不是报错,这说明var将变量的声明提升//varnum;num=10;console.log(num);//打印10,var将变... 查看详情

浅谈var,let,const(代码片段)

...之前使用,而到了ES6之后官方就不推荐使用了,究其原因还是因为它自身的原因,导致代码令人感觉不太合理。console.log(num);varnum=10;//打印undefined,而不是报错,这说明var将变量的声明提升//varnum;num=10;console.log(num);//打印10,var将变... 查看详情

浅谈var,let,const(代码片段)

...之前使用,而到了ES6之后官方就不推荐使用了,究其原因还是因为它自身的原因,导致代码令人感觉不太合理。console.log(num);varnum=10;//打印undefined,而不是报错,这说明var将变量的声明提升//varnum;num=10;console.log(num);//打印10,var将变... 查看详情

浅谈var,let,const(代码片段)

...之前使用,而到了ES6之后官方就不推荐使用了,究其原因还是因为它自身的原因,导致代码令人感觉不太合理。console.log(num);varnum=10;//打印undefined,而不是报错,这说明var将变量的声明提升//varnum;num=10;console.log(num);//打印10,var将变... 查看详情

浅谈var,let,const(代码片段)

...之前使用,而到了ES6之后官方就不推荐使用了,究其原因还是因为它自身的原因,导致代码令人感觉不太合理。console.log(num);varnum=10;//打印undefined,而不是报错,这说明var将变量的声明提升//varnum;num=10;console.log(num);//打印10,var将变... 查看详情

浅谈var,let,const(代码片段)

...之前使用,而到了ES6之后官方就不推荐使用了,究其原因还是因为它自身的原因,导致代码令人感觉不太合理。console.log(num);varnum=10;//打印undefined,而不是报错,这说明var将变量的声明提升//varnum;num=10;console.log(num);//打印10,var将变... 查看详情

let&const(代码片段)

...sole.log(b)//可以重新赋值letc=5console.log(c)//提示c已经定义过const具有和let一样的特性1.const只能定义常量,不能修改2.const不能先定义再赋值 必须定义的同时初始化consta=124 查看详情

let关键字和const关键字

在ES6中,提供了let关键字和const关键字。let的声明方式与var相同,用let来代替var来声明变量,就可以把变量限制在当前代码块中。使用const声明的是常量,其值一旦被设定便不可被更改。 let允许你声明一个作用域被限制在块... 查看详情

ES6 JavaScript - const inside 还是 let outside 循环?

】ES6JavaScript-constinside还是letoutside循环?【英文标题】:ES6JavaScript-constinsideorletoutsideloop?【发布时间】:2018-11-2107:25:52【问题描述】:出于性能目的,我想知道ES6JavaScript之间有什么区别:varlist=[...];letitem;//letoutsidetheloopfor(leti=0;i&... 查看详情