繁体   English   中英

如何在 JavaScript 中创建一个未被其引用修改的常量数组?

[英]How to create a constant array that is not modified by its reference in JavaScript?

我很惊讶这发生在 javascript 中,但是当我开发算法时,我注意到了这一点。

REPEL 模式下的 node.js 程序

当我将“mt”数组放入“wm”常量中,并更改“mt”数组中的一个值时,该值将在“wm”数组中更改。 为什么会这样? 我怎样才能让这不会发生?

我问这个是因为我认为“wm”应该包含“mt”数组的副本,除非我直接修改它,否则不应更改。

变量不直接包含对象(包括数组),它们包含对 memory 中其他地方的那些对象的引用 所以你开始:

                       +−−−−−−−−−−−−+
mt:Ref55162−−−−−−−−−−−>|  (array)   |
                       +−−−−−−−−−−−−+
                       | 0: "hola"  |
                       | 1: "adios" |
                       +−−−−−−−−−−−−+

然后当你做const wm = mt; ,您只是在复制参考; 两个变量(常量)都指向同一个数组:

mt:Ref55162−−−−−+
                |
                |      +−−−−−−−−−−−−+
                +−−−−−>|  (array)   |
                |      +−−−−−−−−−−−−+
                |      | 0: "hola"  |
wm:Ref55162−−−−−+      | 1: "adios" |
                       +−−−−−−−−−−−−+

(该 Ref55162 值仅用于说明;您永远不会在 JavaScript 代码中看到 object 引用的实际值。)

如果你想复制一个数组,你有多种选择:

  1. sliceconst wm = mt.slice();

  2. Array.from : const wm = Array.from(mt);

  3. 扩展符号: const wm = [...mt];

  4. concat[].concat(mt)

请注意,#2 - #4 理论上涉及临时对象,但如果此代码位于性能关键区域,则这些临时对象可能会被优化掉。 #1 不涉及任何临时对象。 (好吧,即使是最后一个,理论上规范描述了创建一个词法环境 object 来调用slice ,但在实践中,实现并不总是必须逐字创建这些对象并尽可能避免它。)

值得指出的是,如果您有一个包含 object 引用的数组,那么就像wd = mt一样,以上所有内容都会为您提供一个包含引用副本的新数组。 因此,如果您有:

const a = [{value: 1}, {value: 2}];
const b = a.slice();

...现在ab是不同的 arrays,但 arrays 都包含对相同两个对象的引用:

                +−−−−−−−−−−−−−+  +−−−−−−−−−−−−−−−−−+
a:Ref14785−−−−−>|   (array)   |  |                 |
                +−−−−−−−−−−−−−+  \   +−−−−−−−−−−+  |
                | 0: Ref55463 |−−−+−>| (object) |  |
                | 1: Ref16839 |−−+   +−−−−−−−−−−+  |
                +−−−−−−−−−−−−−+  |   | value: 1 |  |
                                 |   +−−−−−−−−−−+  |
                                 |                 |
                                 \   +−−−−−−−−−−+  |
                                  +−>| (object) |  |
                                 /   +−−−−−−−−−−+  |
                                 |   | value: 2 |  |
                                 |   +−−−−−−−−−−+  |
                +−−−−−−−−−−−−−+  |                 |
b:Ref98464−−−−−>|   (array)   |  |                 |
                +−−−−−−−−−−−−−+  |                 |
                | 0: Ref55463 |−−|−−−−−−−−−−−−−−−−−+
                | 1: Ref16839 |−−+
                +−−−−−−−−−−−−−+

如果您想复制这些对象,则必须故意这样做,例如:

const b = a.map(obj => ({...obj}));

map为数组中的每个条目调用回调,并根据返回值构建一个新数组; {...obj}将自己的可枚举属性从 object 复制到新的 object 中。

或者如果a是 arrays 的数组,您可以这样做:

const b = a.map(array => array.slice());

(这继续。如果内部 object 或数组包含 object,则引用,然后...)

如果您想一直复制(“深度”复制),这个问题的答案可能很有用:在 JavaScript 中深度克隆 object 的最有效方法是什么?


或者,如果您希望数组不可修改,您可以对其使用freeze

Object.freeze(mt);

那你根本改变不了。

当您将wm分配给mt时,它不会复制数组,而是创建对该数组的引用,因此当您修改原始数组时,它也会修改wm

你可以通过使用Array.prototype.slice来解决这个问题。

所以:

const wm = mt.slice();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM