【问题标题】:Why are constants considered as mutable in Javascript, when only partially true?为什么常量在 Javascript 中被认为是可变的,当仅部分为真时?
【发布时间】:2023-03-16 04:07:01
【问题描述】:

在 Javascript 中,由 MDN documentation 指定:

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

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

【问题讨论】:

    标签: typescript pointers enums constants immutability


    【解决方案1】:

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

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

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

    如果那个地方是一个对象,有很多方法可以改变它(Object.prototype.assigndelete 关键字,属性赋值)。对于原始类型,除了更改其标识符(const 不允许这样做)之外,没有其他方法可以取消引用(“抓取”)内容。这就是为什么常量基元是不可变的而常量对象不是的原因。

    【讨论】:

      【解决方案2】:

      这是一个很好的问题,让我们有机会澄清 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-24
        • 2015-02-18
        • 2015-03-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多