const关键字的秘密:为什么它不总是像你想象的那样

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一时间和你分享前端行业趋势,学习途径等等。
更多开源作品请看 GitHub github.com/qq449245884… ,包含一线大厂面试完整考点、资料以及我的系列文章。

快来免费体验ChatGpt plus版本的,我们出的钱
体验地址:chat.waixingyun.cn
可以加入网站底部技术群,一起找bug.

该文章讲解了 JavaScript 中 const 关键字的用法以及它的一些特性。该关键字用于创建常量,即一旦赋值之后就不能再修改。但是,使用 const 创建的对象和数组却可以被修改。本文通过讲解“赋值”和“变异”之间的重要区别,详细解释了这一现象。

文章首先介绍了变量的三种声明方式:varletconst。它解释了这三种方式的区别,以及为什么使用 const 声明常量。然后,文章深入探讨了“赋值”和“变异”的区别,这是理解 const 的关键。虽然 const 创建的对象和数组。

正文开始

JavaScript 中的 const 关键字用于声明常量。常量通常被认为是“不能更改的变量”:

const hi = 5;
hi = 10;
// 🛑 Uncaught TypeError: Assignment to constant variable.
console.log(hi);
// -> 5

有趣的是,当我使用const创建一个对象时,我可以自由地更改它:

const person = {
  name: 'Hassan',
};
person.name = 'Sujata';
// Seems to work?? 🤔
console.log(person);
// -> { name: 'Sujata' }

我怎么能够改变 person 变量?我使用了 const

为了理解这个表面上的矛盾,我们需要了解赋值和变异之间的区别。这是 JavaScript 中的核心概念,当您清楚地理解这个区别时,许多事情就会变得更加清晰。

变量名作为标签

下面是完全有效的JavaScript程序:

5;

这是另一个:

['apple', 'banana', 'cherry'];

在这两个例子中,我正在创建一些东西。一个数字和一个数组。当代码运行时,这些数据将被创建并存储在计算机的内存中。

这些程序并不是非常有用。我正在创建一些数据,但我没有访问它的方式!

变量允许我们在我们创建的东西上贴上标签,以便以后可以引用它。

// Create it now...
const fruits = ['apple', 'banana', 'cherry'];

// ...and access it later:
console.log(fruits);
// -> ['apple', 'banana', 'cherry']

当我刚开始学习编程时,我认为代码是从左到右执行的:首先我们创建一个 fruits 变量,就像一个空盒子,然后我们在这个盒子里组装我们的数组。

原来这并不是正确的心理模型。更准确的说法是,数组首先被创建,然后我们将我们的 fruits 标签指向它。

重新分配我们的标签

当我们使用 let 关键字创建一个变量时,我们能够更改该标签所引用的“事物”。

例如,我们可以将我们的 fruits 标签指向一个新值:

const关键字的秘密:为什么它不总是像你想象的那样

这被称为重新分配。实际上, fruits 标签应该指向一个完全不同的值:

// We start with a labeled array:
  let fruits = ['apple', 'banana', 'cherry'];

// ⚠️⚠️⚠️⚠️
// 从上面的列表中选择其他选项
//查看它如何在代码中翻译!

我们没有修改数据,我们修改的是标签。我们将其从原始数组中分离出来,连接到一个新数组中。

相比之下,使用 const 创建的变量无法重新赋值:

const关键字的秘密:为什么它不总是像你想象的那样

这是 letconst 之间的根本区别。当我们使用 const 时,我们创建了一个不可摧毁的链接,将变量名和一段数据联系在一起。

然而,问题在于:我们仍然可以修改数据本身!只要标签保持完好无损。

例如,使用数组,我们可以轻松地添加/删除其中的项目。 fruits 变量仍然连接到同一个数组:

const关键字的秘密:为什么它不总是像你想象的那样

这被称为变异(mutation)。我们通过添加/删除项目来编辑数组的值。

这是另一个例子,使用对象而不是数组。只要标签继续指向相同的对象,我们就可以编辑对象中的键/值。

const关键字的秘密:为什么它不总是像你想象的那样

重新分配(将变量名称指向新事物)和突mutation (编辑事物内的数据)之间存在根本区别。

当我们使用 const 创建一个常量时,我们可以百分之百地确定该变量永远不会被重新分配,但是在变异方面没有任何承诺。 const 并不完全阻止变异。

这里还有一个问题:像字符串和数字这样的“原始”数据类型是不可变的。这使得事情变得更加混乱。我们将在下一节中讨论。

如果你正在寻找一种方法来确保你的数据不会被修改,那么有一个方法叫做Object.freeze(),它可以派上用场。使用该方法可以将对象和数组冻结,使它们变成只读的,这样就可以保护它们免受修改。这是一种非常有用的方法,特别是在需要确保数据的不可变性时。使用这种方法,即使使用const关键字也可以确保你的数据不会被修改

// With arrays:
const arr = Object.freeze([1, 2, 3]);
arr.push(4);
console.log(arr);
// -> [1, 2, 3]


// With objects:
const person = Object.freeze({ name: 'Hassan' });
person.name = 'Sujata';
console.log(person);
// -> { name: 'Hassan' }

据我所知,Object.freeze()是防弹的。无法修改使用此方法冻结的对象/数组。

同样,如果你使用TypeScript,你也可以使用as const断言来实现类似的结果

const arr = [1, 2, 3] as const;
arr.push(4);
// 🛑 Error: Property 'push' does not exist
//           on type 'readonly [1, 2, 3]'.

与所有静态类型一样,当代码被编译为JavaScript时,这些保护就会消失,因此这并不能提供与Object.freeze()相同数量的保护。

原始数据类型

到目前为止,我们看到的所有示例都涉及对象和数组。但是如果我们有一个“原始”数据类型,例如字符串、数字或布尔值,该怎么办呢?

以一个数字为例:

let age = 36;
age = 37;

我们应该如何解释这个?我们是将 age 标签重新分配给一个新值,还是突变这个数字,将 36 编辑为 37

这就是问题所在:JavaScript 中的所有原始数据类型都是不可变的。无法“编辑”数字的值。我们只能将变量重新分配给不同的值。

假装有一个包含所有可能数字的大列表。我们已经将 age 变量分配给数字36,但我们可以将它指向列表中的任何其他数字:

const关键字的秘密:为什么它不总是像你想象的那样

要明确的是,浏览器并没有所有可能数字的大索引。我希望在这里阐述的重点是数字本身无法更改。我们只能更改标签指向的数字。

这适用于所有原始值类型,包括字符串、布尔值、null等。

如上所述,在JavaScript中,原始值是不可变的;它们不能被编辑。但如果他们能做到呢?如果数字本身可以改变,那么语法会是什么样子呢?它看起来是这样的:

// 编辑数字36的值
36 = 37;

// 36这个数字不再存在了
console.log(36); // 37

所以,如果我们可以在JavaScript中改变原始值,那就意味着基本上覆盖某些数字,这样它们就永远不会再被引用了!这显然会让人感到困惑和无助,这就是为什么在JavaScript中基本类是不可变的。

编辑中可能存在的bug没法实时知道,事后为了解决这些bug,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

交流

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub github.com/qq449245884… 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

原文链接:https://juejin.cn/post/7234505799455555644 作者:王大冶

(0)
上一篇 2023年5月19日 上午10:20
下一篇 2023年5月19日 上午10:31

相关推荐

发表回复

登录后才能评论