这是一个很好的问题,让我们有机会澄清 Javascript 作为一种语言的一些更大的细微差别。
理解指针
在某些编程语言中,有一个概念是指针。指针是包含另一个指针地址的变量。因此,在像 c 这样的语言中,只读且可变的 const 更为明显:
#include <stdio.h>
int main(){
const int counter = 0;
*(int *)&counter = 39;
printf("%d", counter);
}
在上面的 C 代码中,我们创建了一个对 0 的只读引用。但是,通过使用指针,我们强制转换一个指向计数器的值,然后再次指向该值。计数器不会将其视为直接更改值。所以我们看到,在使用指针的语言中,这样的代码是可以做到的。
但是,问题就变成了,没有指针概念的 Javascript 怎么办?也许在 Object 或 Array 以外的情况下的 const 应该被认为是不可变的。
Javascript 作为原型语言
然后进入下一点。 Javascript 是一种原型语言。这意味着,Javascript 中的所有内容最终都由相互构建的对象表示。记住这些知识,我们所要做的就是爬到可用的 AKA 文档或窗口的最高对象。
利用我们对指针和原型的了解
因此,即使是 Javascript 中的 const 这样的只读值,理论上也应该有某种变异方式。所以问题是,一个人怎么能继续这样做呢?
代码示例 - 改变一个常量
const test = 'foo';
window['test'] = 'value mutated';
console.log(test);
// value emitted 'value mutated'
在上面的代码示例中,将被控制台输出的值将是value mutated。这是因为在任何浏览器设置中,window + document 对象都会缓存所有变量。这允许值被变异,因为编译器不会注册为只读值被变异。我们正在使用窗口创建一个指针(可以这么说),它创建了另一个参考点。所以是的,一个 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