为什么常量在 Javascript 中被认为是可变的,而只有部分为真?
Why are constants considered as mutable in Javascript, when only partially true?
在Javascript中,由MDN documentation指定:
The const declaration creates a read-only reference to a value. It
does not mean the value it holds is immutable, just that the variable
identifier cannot be reassigned. For instance, in the case where the
content is an object, this means the object's contents (e.g., its
properties) can be altered
但是,尝试更改字符串或数字会出错,如 TypeError: invalid assignment to const
。如果是这样,为什么在 const 是数组或对象以外的值的任何情况下,const 不被视为可变的?
这是一个很好的问题,它提供了澄清 Javascript 作为一种语言的一些更细微差别的机会。
理解指针
在某些编程语言中,有指针的概念。指针是包含另一个指针地址的变量。因此,在像 c 这样的语言中,const 是只读和可变的更明显:
#include <stdio.h>
int main(){
const int counter = 0;
*(int *)&counter = 39;
printf("%d", counter);
}
在上面的 C 代码中,我们创建了一个对 0 的只读引用。但是,通过使用指针,我们转换了一个指向计数器的值,然后再次指向该值。 Counter 不会将其视为直接更改值。所以我们看到在使用指针的语言中,这样的代码是可以做到的。
但是,那么问题就变成了,没有指针概念的Javascript呢?也许在 Object 或 Array 以外的情况下的 const 应该被认为是不可变的。
Javascript 作为原型语言
然后进入下一点。 Javascript 是一种原型语言。这意味着,Javascript 中的所有内容最终都由相互构建的对象表示。记住这些知识,我们所要做的就是抓取到可用的最高对象 AKA 文档,或 window。
利用我们的指针和原型知识
因此,即使 Javascript 中的 const 这样的只读值在理论上也应该有某种变异方式。所以问题是,如何才能继续这样做呢?
代码示例 - 改变一个 Const
const test = 'foo';
window['test'] = 'value mutated';
console.log(test);
// value emitted 'value mutated'
在上面的代码示例中,将被控制台输出的值将为 value mutated
。这是因为在任何浏览器设置中, window + 文档对象都会缓存所有变量。这允许值被改变,因为编译器不会注册为只读值被改变。我们正在使用 window 在值上创建一个指针(可以这么说),这会创建另一个参考点。所以是的,const 对于字符串或数字以外的值是可变的,即使它是只读值!
代码示例 -(尝试)改变枚举
尝试改变 Typescript 中的不可变枚举
enum testTwo {
test = 'value immutable'
}
const pointerToTestTwo = 'testTwo.test';
window[testTwo.test] = 'value mutated';
console.log(testTwo.test);
// value emitted 'value immutable'
将不起作用。这是因为 typescript 中的枚举被编译为 IIFE(立即调用函数表达式),没有参考点。更改枚举的唯一方法是创建另一个引用枚举的函数。
所以是的,结束这一点。在所有情况下,只读 const 在 Javascript 中确实是可变的,而 Typescript 中的枚举是不可变的。请随时查看我的文章,其中对此进行了更多讨论:Enums V. Constants
However, trying to alter a string, or number, will error out as TypeError: invalid assignment to const
这正是文档所说的 — 无法重新分配变量标识符。
一个const
标识符总是指向同一个地方。但是,这个地方的内容可能会改变。
如果那个地方是一个对象,有很多方法可以改变它(Object.prototype.assign
,delete
关键字,属性 赋值)。对于原始类型,除了更改其标识符(const
不允许这样做)之外,没有其他方法可以取消引用(“获取”)内容。这就是为什么常量基元是不可变的而常量对象不是。
在Javascript中,由MDN documentation指定:
The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in the case where the content is an object, this means the object's contents (e.g., its properties) can be altered
但是,尝试更改字符串或数字会出错,如 TypeError: invalid assignment to const
。如果是这样,为什么在 const 是数组或对象以外的值的任何情况下,const 不被视为可变的?
这是一个很好的问题,它提供了澄清 Javascript 作为一种语言的一些更细微差别的机会。
理解指针
在某些编程语言中,有指针的概念。指针是包含另一个指针地址的变量。因此,在像 c 这样的语言中,const 是只读和可变的更明显:
#include <stdio.h>
int main(){
const int counter = 0;
*(int *)&counter = 39;
printf("%d", counter);
}
在上面的 C 代码中,我们创建了一个对 0 的只读引用。但是,通过使用指针,我们转换了一个指向计数器的值,然后再次指向该值。 Counter 不会将其视为直接更改值。所以我们看到在使用指针的语言中,这样的代码是可以做到的。
但是,那么问题就变成了,没有指针概念的Javascript呢?也许在 Object 或 Array 以外的情况下的 const 应该被认为是不可变的。
Javascript 作为原型语言
然后进入下一点。 Javascript 是一种原型语言。这意味着,Javascript 中的所有内容最终都由相互构建的对象表示。记住这些知识,我们所要做的就是抓取到可用的最高对象 AKA 文档,或 window。
利用我们的指针和原型知识
因此,即使 Javascript 中的 const 这样的只读值在理论上也应该有某种变异方式。所以问题是,如何才能继续这样做呢?
代码示例 - 改变一个 Const
const test = 'foo';
window['test'] = 'value mutated';
console.log(test);
// value emitted 'value mutated'
在上面的代码示例中,将被控制台输出的值将为 value mutated
。这是因为在任何浏览器设置中, window + 文档对象都会缓存所有变量。这允许值被改变,因为编译器不会注册为只读值被改变。我们正在使用 window 在值上创建一个指针(可以这么说),这会创建另一个参考点。所以是的,const 对于字符串或数字以外的值是可变的,即使它是只读值!
代码示例 -(尝试)改变枚举
尝试改变 Typescript 中的不可变枚举
enum testTwo {
test = 'value immutable'
}
const pointerToTestTwo = 'testTwo.test';
window[testTwo.test] = 'value mutated';
console.log(testTwo.test);
// value emitted 'value immutable'
将不起作用。这是因为 typescript 中的枚举被编译为 IIFE(立即调用函数表达式),没有参考点。更改枚举的唯一方法是创建另一个引用枚举的函数。
所以是的,结束这一点。在所有情况下,只读 const 在 Javascript 中确实是可变的,而 Typescript 中的枚举是不可变的。请随时查看我的文章,其中对此进行了更多讨论:Enums V. Constants
However, trying to alter a string, or number, will error out as
TypeError: invalid assignment to const
这正是文档所说的 — 无法重新分配变量标识符。
一个const
标识符总是指向同一个地方。但是,这个地方的内容可能会改变。
如果那个地方是一个对象,有很多方法可以改变它(Object.prototype.assign
,delete
关键字,属性 赋值)。对于原始类型,除了更改其标识符(const
不允许这样做)之外,没有其他方法可以取消引用(“获取”)内容。这就是为什么常量基元是不可变的而常量对象不是。