关键字“const”不会使值不可变。这是什么意思?

IT技术 javascript ecmascript-6 常数
2021-01-20 03:15:12

Axel Rauschmayer 博士Exploring ES6 中const 定义

const和 let 一样工作,但是你声明的变量必须立即初始化,并带有一个以后不能改变的值[…]

const bar = 123;
bar = 456;  // TypeError: `bar` is read-only

然后他写

陷阱:const 不会使值不可变

const 仅意味着变量始终具有相同的值,但并不意味着该值本身是或变为不可变的。

我对这个陷阱有点困惑。任何人都可以清楚地定义const这个陷阱吗?

5个回答

当你const在 JavaScript 中创建一些东西时,你不能重新分配变量本身来引用其他东西。但是,变量仍然可以引用可变对象。

const x = {a: 123};

// This is not allowed.  This would reassign `x` itself to refer to a
// different object.
x = {b: 456};

// This, however, is allowed.  This would mutate the object `x` refers to,
// but `x` itself hasn't been reassigned to refer to something else.
x.a = 456;

对于字符串和数字等基元,const理解起来更简单,因为您不会改变值,而是为变量分配一个新值。

这个答案比公认的要好得多。更简洁并包含实际示例代码。(换句话说,切入正题。)+1
2021-03-13 03:15:12

MDN总结得很好:

const声明创建了一个对值的只读引用。这并不意味着它持有的值是不可变的,只是变量标识符不能重新分配。例如,如果内容是一个对象,这意味着对象本身仍然可以更改。

更简洁:const创建一个不可变的绑定。

换句话说:const,像var,给你一个可变的内存块,你可以在其中存储一些东西。然而,const 规定你必须继续引用同一块内存——你不能将变量重新分配给不同的内存块,因为变量引用是常量。

要在声明之后真正使某些内容保持不变且不变,您需要使用类似Object.freeze(). 但是,这是浅薄的,仅适用于键/值对。冻结整个对象需要更多的努力。以高效的方式重复执行此操作更具挑战性。如果你真的有这个需要,我建议你看看Immutable.js 之类的东西

在 C 术语中:如果法线var x是 a struct Object *x,则 aconst x是 a struct Object *const x指针不能改变;它指向的东西可以。
2021-03-16 03:15:12

重新装订

constlet声明控制是否允许标识符和值之间的重新绑定(也称为重新分配):

const x = "initial value";
let y = "initial value";

// rebinding/reassignment

try { x = "reassignment" } catch(e) { console.log(x) } // fails

y = "reassignment"; // succeeds
console.log(y);

不变性

不变性是在类型级别控制的。Object是可变类型,而String是不可变类型:

const o = {mutable: true};
const x = "immutable";

// mutations

o.foo = true; // succeeds
x[0] = "I"; // fails

console.log(o); // {mutable: true, foo: true}
console.log(x); // immutable

const 意味着:您不能更改最初分配的值。

首先,定义一下js中是什么值可以是:布尔值、字符串、数字、对象、函数和未定义的值。

比如:人们用你的名字称呼你,它没有改变。然而,你换了衣服。结合和人民之间,你是你的名字。其余的可以改变。对不起,奇怪的例子。

那么,让我给你举几个例子:

// boolean
const isItOn = true;
isItOn = false;           // error

// number
const counter = 0;
counter++;                // error

// string
const name = 'edison';
name = 'tesla';           // error

// objects
const fullname = {
  name: 'albert',
  lastname: 'einstein'
};

fullname = {              // error
  name: 'werner',
  lastname: 'heisenberg'
};
// NOW LOOK AT THIS:
//
// works because, you didn't change the "value" of fullname
// you changed the value inside of it!
fullname.name = 'hermann';

const increase = aNumber => ++aNumber;
increase = aNumber => aNumber + 1;      // error

// NOW LOOK AT THIS:
//
// no error because now you're not changing the value
// which is the decrease function itself. function is a
// value too.
let anotherNumber = 3;
const decrease = () => --anotherNumber;

anotherNumber = 10;             // no error
decrease();                     // outputs 9

const chaos = undefined;
chaos = 'let there be light'    // error

const weird = NaN;
weird = 0                       // error

如您所见,除非您没有将“第一个”分配的值更改为常量,否则不会出错。每当您尝试将第一个分配的值更改为其他值时,它就会生气,并给出错误。

因此,这是您在使用const. 也就是说,它应该在其声明中初始化为一个值,否则它会生气。

const orphan;                    // error
const rich = 0;                  // no error

ES6/ES2015 const关键字:

所述const关键字被用于声明的块范围的变量(如使用声明let)。使用const声明变量的区别let如下:

  1. 声明的变量 const不能重新赋值
  2. 声明为 的变量const必须声明赋值这是上一点的逻辑结果,因为用 声明的变量不能重新分配,这就是为什么我们必须在声明变量时只分配一次const

例子:

// we declare variable myVariable
let myVariable;

// first assignment
myVariable = 'First assingment';
// additional assignment
myVariable = 'Second assignment';

// we have to declare AND initialize the variable at the same time
const myConstant = 3.14;

// This will throw an error
myConstant = 12;

在上面的例子中,我们可以观察到以下内容:

  1. myVariable声明的变量let可以先声明,然后再赋值。
  2. myConstant声明的变量const必须同时声明和赋值。
  3. 当我们尝试重新分配变量时myConstant,会出现以下错误:

未捕获的类型错误:赋值给常量变量

警告:分配给的变量const仍然是可变的:

constjust声明的变量不能重新赋值,它仍然是 mutable可变意味着分配给const变量的数据结构(对象、数组、映射等)仍然可以改变(即变异)。突变的例子是:

  1. 添加/删除/更改对象的属性
  2. 更改特定数组索引处的数组值

如果真的希望对象不可变,则必须使用类似Object.freeze(). 这是一种冻结对象的方法。无法再更改冻结对象,也无法添加新属性。

例子:

const obj = {prop1: 1};

obj.prop1 = 2;
obj.prop2 = 2;

console.log(obj);

// We freeze the object here
Object.freeze(obj);

obj.prop1 = 5;
delete obj.prop2;

// The object was frozen and thus not mutated
console.log(obj);