为什么常量只在部分正确的情况下被视为Javascript中的可变变量?

时间:2019-03-05 02:32:07

标签: typescript pointers enums const immutability

在Java中,由MDN documentation指定:

  

const声明创建对值的只读引用。它   并不意味着它拥有的值是不可变的,只是那个变量   标识符无法重新分配。例如,如果   content是一个对象,这意味着该对象的内容(例如,   属性)可以更改

但是,尝试更改字符串或数字将错误显示为TypeError: invalid assignment to const。如果真是这样,为什么在任何const是数组或对象以外的值的情况下,为什么const都不可变?

2 个答案:

答案 0 :(得分:0)

这是一个很好的问题,并为阐明Java语言的某些细微差别提供了机会。

了解指针

在某些编程语言中,有一个概念作为指针。指针是包含另一个指针的地址的变量。因此,在像c这样的语言中,更易读和可变的const更加明显:

#include <stdio.h>
int main(){
    const int counter = 0;
    *(int *)&counter = 39;
    printf("%d", counter);
}

在上面的C代码中,我们创建一个对0的只读引用。但是,通过使用指针,我们强制转换了一个指向counter的值,然后再次指向该值。柜台不会将其视为直接改变价值。因此,我们看到在使用指针的语言中,这样的代码是可行的。

但是,问题就变成了,对于没有概念作为指针的Javascript呢?在对象或数组以外的情况下,常量可能被认为是不可变的。

Java语言作为原型语言

然后转到下一点。 Javascript是一种原型语言。这意味着,Javascript中的所有内容最终都由相互构建的对象表示。要记住这些知识,我们要做的就是爬到可用的最高对象的AKA文档或窗口。

利用我们对指针和原型的了解

因此,即使是只读值,例如Java中的const,从理论上讲也应该具有某种变异的方式。所以问题是,一个人怎么能做到这一点呢?

代码示例-更改常量

const test = 'foo';
window['test'] = 'value mutated';
console.log(test);
// value emitted 'value mutated'

在上面的代码示例中,将被调出的值将为value mutated。这是因为在任何浏览器设置中,窗口+文档对象都会缓存所有变量。因为编译器不会注册为要更改的只读值,所以这允许值被更改。我们正在使用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'

不起作用。这是因为打字稿中的枚举被编译为没有参考点的IIFE(立即调用函数表达式)。更改枚举的唯一方法是创建另一个引用枚举的函数。

是的,结束这一点。实际上,在所有情况下,只读const在Javascript中都是可变的,与Typescript中的枚举相反,后者是不可变的。请随意看一下我的文章,该文章对此进行了更多讨论:Enums V. Constants

答案 1 :(得分:0)

  

但是,尝试更改字符串或数字将错误为TypeError: invalid assignment to const

这正是文档所说的-变量标识符不能重新分配

const标识符将始终指向同一位置。但是,这个地方的内容可能会改变。

如果该地方是一个对象,则有多种方式对其进行突变(Object.prototype.assigndelete关键字,属性分配)。对于原始类型,除了更改其标识符(const不允许)之外,没有其他方法可以取消引用(“抢夺”)内容。这就是常量原语是不变的而常量对象不是不变的原因。