前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >不可变和ES6中的const

不可变和ES6中的const

作者头像
疯狂的技术宅
发布2019-03-28 10:24:40
4550
发布2019-03-28 10:24:40
举报
文章被收录于专栏:京程一灯京程一灯

前言

在很多人的意识中,JS里的const变量仿佛就是其他语言中的常量一样完全不可变,——这样理解const的作用当然是完全错误的,然而不幸的是这种误解从没消失过,甚至还相当流行。本文将会直截了当的将const的真正作用展现出来。

正文

ES6中的const创造的是一种不可变得binding(绑定),这不代表被const定义的变量是一个constant(常量)或是immutable(不可变的)。一个const变量是可以改变的。下面的例子就为你们展示这一点,这段代码是完全合法的ES6代码,并且不会抛出异常:

代码语言:javascript
复制
const foo = {};foo.bar = 42;console.log(foo.bar);// → 42

在这段代码里,对于const变量来讲唯一不可变的是binding,即const分配给变量名foo一个值:{},并且保证这种分配操作不会再次发生(译者:但他里面的值{}怎么变不保证)。对于可能造成重新分配的操作,如使用任何assignment operator、unary或postfix操作都会导致抛出TypeError异常,请看下面的测试:

代码语言:javascript
复制
const foo = 27;// 以下操作都会抛出异常// Assignment operators:foo = 42;foo *= 42;foo /= 42;foo %= 42;foo += 42;foo -= 42;foo <<= 0b101010;foo >>= 0b101010;foo >>>= 0b101010;foo &= 0b101010;foo ^= 0b101010;foo |= 0b101010;// Unary `--` and `++`:--foo;++foo;// Postfix `--` and `++`:foo--;foo++;

由此可见,ES6的const做到的是保证变量分配上的不可变,而非值上的不可变(译者:尽管对于基本数据类型的变量来讲这俩好像是一回事)。

那么,如何让一个变量内部的值不可变?

对于基本数据类型(number, string, boolean, symbol, null, undefined)来讲它们内部的值是不可变的,不管你怎么定义它们:

代码语言:javascript
复制
var foo = 27;foo.bar = 42;console.log(foo.bar);// → `undefined`

如果你想让一个对象的值不可变,可以使用Object.freeze()。这个方法从ES5开始被支持,到现在已经被广泛使用。

代码语言:javascript
复制
const foo = Object.freeze({
	'bar': 27});foo.bar = 42; // strict mode下会抛出TypeError异常;// sloppy mode下不会报错,但赋值也不会成功;console.log(foo.bar);// → 27

值得注意的是,Object.freeze()的效果并不保证整个对象完全的、绝对的无法改变:一个已经freeze了的对象的值仍然是可以发生变化,比如嵌套对象,例:

代码语言:javascript
复制
obj1 = {
  internal: {}};Object.freeze(obj1);obj1.internal.a = 'aValue';console.log(obj1.internal.a)// 'aValue'

如果想要保证整个变量是彻底的不可变,你可以参考这个链接(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)里面deepFreeze()方法的实现来达到这个目的(译者:这个deepFreeze简单来讲就是用递归的方法遍历内部所有的对象并给他们加上freeze)。

另外要说的是,Object.freeze()只适用于property-value pairs(属性值对)这种形式,所以你没办法让Date、Map或是Set这种对象完全不可变。

补充一点:现在有个提议就是关于在未来的ECMAScript标准中增加一种完全不可变的数据结构。

const vs. let

const和let唯一的区别是,const让rebinding(重新绑定)不能发生。

本文写到这里都是基于事实的内容,接下来我说点主观的东西。基于上面我们所了解的,我认为使用const让代码更易于阅读,一个const变量总是指向同一个object(译者:而且你可以改变对象内的值),let则完全不能保证这一点(译者:即无法保证总是指向同一object)。所以我认为,在ES6代码中使用let还是const基于以下原则是合理的:

1、没有特殊情况都用const

2、只有需要rebinding的时候(译者:如基本数据类型变量的改变)才使用let

3、不管你怎么用let或者const,都不要在ES6代码里用var

不知道你同意吗?同意或反对的理由是什么?我对那些更习惯使用let的开发者的意见很感兴趣(即便他们将let使用在那些从来不会变化的变量上),为什么当你定义那些不会重新bind的变量时第一个会想到使用let?是因为“const定义的是常量”这种概念上的错误理解,还是别的什么原因?欢迎你们留言写下自己的理由。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档