9月7日-8日,相约 2023 腾讯全球数字生态大会!聚焦产业未来发展新趋势! 了解详情
写点什么

JavaScript 常量真的不可变吗?

  • 2019-07-07
  • 本文字数:2283 字

    阅读完需:约 7 分钟

JavaScript常量真的不可变吗?

JavaScript 中的常量究竟如何工作,常量就是“在正常执行中无法被程序改变的值”吗?事实就是如此吗?非也,本文将给你答案。


前几天我在 Twitter 上谈到了 JavaScript 中的 const。Kyle Simpson 指出我之前分享的一篇文章中有关于 const 的一个误解。但我的想法是,至少我能理解这种糊涂来自哪里,因为 const 与我预想的工作方式不太一样(注,我并不是说 const 是错的,只是说它与我的预想有差别。)



虽然我跟 Kyle Simpson 对话很短,但是这段对话仍然涉及到了许多词汇和概念。因此我觉得自己不妨深入研究一下,从而使自己不仅更加理解常量的概念,而且更加了解用 const 声明的变量在 JavaScript 中到底是如何工作的。


需要指出的是,Kyle Simpson 的确写过一篇关于此主题的帖子,但是这篇博客已经下线了。而且他的确通过Wayback Machine分享过一个版本。这篇博客值得一读,因为他写得很深入。

什么是常量

如果你在谷歌搜“什么是编程中所谓的常量?”,你会发现许多页面将常量定义为维基百科中定义的那样,即“在正常执行中无法被程序改变的值。”


表面上看,这似乎很简单,就是设置一个值,一个无法改变的值。这对于可读性和错误检查会十分有用。但是,并非所有语言都有常量,而且拥有常量的各个语言处理常量的方式也不太一样。例如,在一些语言中,常量所代表的值的类型是有限的。


一旦你走出简单的值类型范围后,事情就会变得令人糊涂了。这一点很重要,这也是我对 JavaScript 中的常量感到糊涂的起点。这里,我会举一个例子,而不是解释。


现在,假设我要像这样设置一个常量:


const NAME = "Brian";
复制代码


似乎很明显的是,给 NAME 指定任何新的值都会出现错误。但是,如果我像下面这样做呢:


const ME = {name:'Brian'};
复制代码


如果我改变 ME.name 的值,是否还会出错?有人会说本质上我并没有改变 ME 的值,因为它仍然指向同样的对象,即使这个对象已经被改变了。但要说明的是,在 JavaScript 中,这并不会出错。



在这里,会出现计算机科学家们熟悉的概念,那就是基元和不变性。我们会谈一点这方面的内容,但为了避免让本文成为一本计算机科学书籍,我不会深入地探讨这两个概念。


简单来说,不可改变的对象是指一个创建后便无法改变其状态的对象。而 JavaScript 中的基元是指“一个不是对象但没有方法的数据。” (来源: MDN)

JavaScript 中的常量

JavaScript ES6(又称 ES2015)中加入了 const 关键词。之前,通常的约定是使用一个标准的变量,但它必须以全大写命名,如 MY_CONSTANT。但这并没有真正规定一个变量是否能够被更改,它只是对程序员的一个提示,提示他们不要更改该变量。


用 const 声明的 JavaScript 常量可以是全局范围的,也可以是区块范围的。如果常量位于区块内(即在{ 和}之间),它们就自动是区块范围的。如果它们没有在区块内,则它们是全局范围的。但是,与用 var 声明的变量不同的是,它们不会成为 window 对象的特性。如果它们位于模块中,位于区块外用 const 声明的变量对于该模块而言将是全局范围的。


const 和 var 另一个有趣的区别在于,它们提升(hoist)的方式不同。当你用 const 或 let 声明一个变量时,该声明将被提升,但是它的初始化值并不是 undefined,因此如果你尝试在声明前访问它的话,会出现引用错误。正如下面所示,第一个 console.log 引用了以 var 定义的变量,它的返回值为 undefined。而第二个 console.log 引用了以 const 定义的变量,却出现了一个错误。



这一现象被称之为暂时性死区,这个名字使它听起来比实际上更加不吉利。


如前所述,最后一条关于 JavaScript const 重要的一点是:


const 声明为一个值创建了一个只读的引用。这并不是说其代表的值是不可改变的,而只是说变量标识符不能被重新指定罢了。(来源


这也是关于 const 的困惑再次出现的地方。当你将 const 用于JavaScript 基元类型(如布尔值、数字、字符串等)时,const 的行为与你预想的一致(任何重新指定值的尝试都会导致错误)。但是,当你将 const 用于JavaScript对象时(包括数列、函数等),这个对象仍然是可以更改的,也就是说,这个对象的特性仍然可以被更改。


想要了解 let 和 const 作用域的详情,请阅读 Axel Rauschmayer 的 “为没耐心的程序员设计的JavaScript”这篇文章。

你应该用 Const 吗?

回答这个问题有点难,特别是因为 let 拥有同样的区块作用域和提升优势(我将后者描述为一个潜在的优势,因为如果你在声明某个变量前不小心访问了某个变量的话,你提升 var 的方式可能会导致出现不太常见的错误)。鼓吹 const 优势的人通常关注于代码的可读性。通过使用 const,你相当于表明了这个特定的变量不应该被更改,并且在某种程度上,你强调了这一点。然而,人们好像经常对此产生误解这一事实把支持 const 可读性的观点给削弱了,就像本文开头所讲的那样。这的确能够一定程度上防止他人重新指定这个变量的值,但是我想引用一下Kyle的话:


事实上,许多程序员都承认,这一保护能够避免一些不知情的程序员意外地改变某个 const。然而,有个例外,我认为在现实中很可能发生的情况是,当一个程序员需要更改某个变量但却获得了一个“const-抛出”错误时,他可能会将 const 直接修改成 let,然后继续工作。


所以,如果 const 提供的保护较为有限的话,那么我们可能只需要在乎风格偏好了,特别是在 let 和 const 之间做选择时。但如果你的变量需要代表一个基元值,而且这个基元值并不会改变,那么很显然,使用 const 是个合理的选择。但是,请注意,如果该值并非一个基元值,那么从可读性的角度来讲,使用 const 会给人带来更多困惑,而不是帮助。


英文原文:https://remotesynthesis.com/blog/javascript-const


活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

2019-07-07 12:374182
用户头像

发布了 34 篇内容, 共 18.1 次阅读, 收获喜欢 46 次。

关注

评论

发布
暂无评论
发现更多内容

Mybatis常考面试题汇总(附答案),学习SpringBoot

Java 程序员 后端

MySQL 事务隔离级别,进阶和基础哪一个难

Java 程序员 后端

架构营模块二作业

GTiger

架构实战营

leetcode 数组练习,java入门书籍

Java 程序员 后端

Mac下vagrant从安装到体验,经典实战教程

Java 程序员 后端

Kubernetes 常用命令大全,震撼来袭免费下载

Java 程序员 后端

MongoDB入门操作汇总,网易架构师深入讲解Java开发

Java 程序员 后端

MyBatis 源码分析 - 插件机制,java容器面试题

Java 程序员 后端

MyEclipse优化、常用设置、快捷键,java视频教程百度云

Java 程序员 后端

Kotlin之DSL,java面试写代码

Java 程序员 后端

Kubernetes官方java客户端之六:OpenAPI基本操作

Java 程序员 后端

MyBatis 自定义 SQL 拦截器,java数据可视化技术

Java 程序员 后端

markdown编辑器的使用教程,java面试笔试题程序题

Java 程序员 后端

MyBatis官方文档-日志,java高级开发工程师职责

Java 程序员 后端

JVM总体概述,java高级开发面试经验

Java 程序员 后端

Kafka-on-Pulsar 的前世今生,新秀 Pulsar 到底好在哪?

Java 程序员 后端

kubernetes部署metrics-server,linux服务器教程

Java 程序员 后端

linux常用命令(一),阿里java面试算法

Java 程序员 后端

Kafka性能调优实战:同等资源配置性能提升20几倍的秘诀

Java 程序员 后端

Linux服务器端网络抓包和分析实战,中高级Java面试题目汇总解答

Java 程序员 后端

MyCat配置文件详解(二),java自学视频谁讲的好

Java 程序员 后端

kubebuilder实战之三:基础知识速览,mybatis运行原理步骤

Java 程序员 后端

MyBaitsPlus----知识盲点整理,mysql数据库项目式教程答案

Java 程序员 后端

Mybatis学习笔记--自定义Mybatis,java程序员面试笔试宝典百度云

Java 程序员 后端

linux防火墙iptables常用操作笔记,java开发手册百度网盘

Java 程序员 后端

MyBatis01:初识 MyBatis 与 第一个 MyBaits 程序

Java 程序员 后端

mybatis开发要点-insert主键ID获取和多参数传递

Java 程序员 后端

JVM篇:对象的深度剖析,mybatis入门程序

Java 程序员 后端

Kubernetes任务调用Job与CronJob及源码分析(1)

Java 程序员 后端

Kurento实战之一:KMS部署和体验,应届毕业生java面试准备

Java 程序员 后端

Contour-v1.19.1发布

远鹏

golang Kubernetes cncf envoy contour

  • 扫码添加小助手
    领取最新资料包
JavaScript常量真的不可变吗?_语言 & 开发_Brian Rinaldi_InfoQ精选文章