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 里也就没再改了。

用 const 还是用 let?的更多相关文章

  1. openssl 1.1.1 reference

    openssl 1.1.1 include/openssl aes.h: # define HEADER_AES_H aes.h: # define AES_ENCRYPT 1 aes.h: # de ...

  2. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  3. C++中的const

    一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...

  4. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  5. const let,console.log('a',a)跟console.log('a'+a)的区别

    const 创建一个只读的常量 let块级作用域 const let重复赋值都会报错 console.log('a',a) a console.log('a'+a) a2 逗号的值会有空格:用加号的值 ...

  6. es6之let和const

    在javascript中,我们都知道使用var来声明变量.javascript是函数级作用域,函数内可以访问函数外的变量,函数外不能访问函数内的变量. 函数级作用域会导致一些问题就是某些代码块内的变量 ...

  7. construction const parameter问题 构造函数const引用参数问题

    工程在window下编译没有任何问题, 但是在linux(CentOS6)下编译就老是报错 C++ 编译器已升级到最新版 6.1.0 错误如下: In file included /bits/stl_ ...

  8. Error:const char* 类型的实参和LPCWSTR类型的形参不兼容的解决方法。

    在C++的Windows 应用程序中经常碰到这种情况. 解决方法: 加入如下转换函数: LPCWSTR stringToLPCWSTR(std::string orig) { size_t origs ...

  9. C#基础知识七之const和readonly关键字

    前言 不知道大家对const和readonly关键字两者的区别了解多少,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态常量和动态常量. 静态常量 所谓静态常量就是在编译期间会对变量 ...

  10. const 与 readonly知多少

    原文地址: http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html 尽管你写了很多年的C#的代码,但是可能当别人问到你cons ...

随机推荐

  1. Windows server用好windows server backup,发挥个人电脑该有的系统还原功能

    笔记本上安装windows server的各位是不是有个感触,默认软件升级.软件更新,系统是没有系统还原的(磁盘清理发现也没有还原点可清理),也就是系统出了问题,还原不了干着急. 其实,windows ...

  2. spring类型自动转换——@InitBinder和Converter

    spring有2种类型转换器,一种是propertyEditor,一种是Converter.虽然都是类型转换,但是还是有细微差别. 所以这里以一个例子的形式来分析一下这2种类型转换的使用场景和差别. ...

  3. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  4. 洛谷P3388 【模板】割点

    给出一个n个点,m条边的无向图,求图的割点. u是cut vertex的两个条件: 1.存在v使v及其所有后代没有反向边连回u的祖先 2.u是根且有两个以上子节点 dfs一遍 low[u]是u及其后代 ...

  5. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  6. hibernate单表junit测试

    首先,创建java project ,导入需要的jar包 添加hibernate.cfg.xml <?xml version='1.0' encoding='UTF-8'?> <!D ...

  7. mysql apach php

    一.MySql MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将 ...

  8. SecureCRT连接虚拟机(ubuntu)配置

    使用SecureCRT连接虚拟机(ubuntu)配置记录   这种配置方法,可以非常方便的操作虚拟机里的Linux系统,且让VMware在后台运行,因为有时候我直接在虚拟机里操作会稍微卡顿,或者切换速 ...

  9. JAVA IDE IntelliJ IDEA使用简介(一)—之界面元素

    (注:简介基于IDEA的版本为:11.0,下载地址:http://www.jetbrains.com/idea/) 打开IDEA,(当第一次打开的时候出现的是一个欢迎页面,随便创建一个project来 ...

  10. Excel到底最多可以有多少行

    平时我们使用的Excel到底最多可以有多少行? 答案:1048576,如图在红框中输入此数字即可看见.