冻结数组的元素

时间:2018-08-30 15:53:54

标签: javascript

我有一些原始元素的数组:

const array = [1, 2, 3]

我希望能够暂时冻结此数组的元素并防止对其进行修改。但是,一旦允许修改该元素,就应该有一种解冻该值的方法。

有办法吗?

将这些问题标记为重复的人的题外话:

问题在于冻结数组的元素,而不是冻结整个数组。这不是关于冻结整个阵列的问题的重复。

1 个答案:

答案 0 :(得分:4)

您不想冻结,而是希望冻结保存该值的属性(该数组的"1"属性您的情况)。您将使用Object.defineProperty重新定义不带writable标志的属性。要使其再次可写,请使用writable: true重新定义它:

const array = [1, 2, 3];
console.log("A", array.join(", ")); // 1, 2, 3

// Freeze it
Object.defineProperty(array, "1", {
  value: array[1],
  writable: false, // For emphasis (this is the default)
  enumerable: true,
  configurable: true
});
console.log("B1", array.join(", ")); // 1, 2, 3
array[1] = 42;                       // <== Doesn't change it
console.log("B2", array.join(", ")); // 1, 2, 3 (still)

// Thaw it
Object.defineProperty(array, "1", {
  value: array[1],
  writable: true,
  enumerable: true,
  configurable: true
});
console.log("C1", array.join(", ")); // 1, 2, 3
array[1] = 42;                       // <== Changes it
console.log("C2", array.join(", ")); // 1, 42, 3 (changed!)

如果执行分配的代码在严格模式下运行,则该分配将是一个例外:

"use strict";
const array = [1, 2, 3];
console.log("A", array.join(", ")); // 1, 2, 3

// Freeze it
Object.defineProperty(array, "1", {
  value: array[1],
  writable: false, // For emphasis (this is the default)
  enumerable: true,
  configurable: true
});
console.log("B1", array.join(", ")); // 1, 2, 3
array[1] = 42;                       // <== Doesn't change it
console.log("B2", array.join(", ")); // 1, 2, 3 (still)

// Thaw it
Object.defineProperty(array, "1", {
  value: array[1],
  writable: true,
  enumerable: true,
  configurable: true
});
console.log("C1", array.join(", ")); // 1, 2, 3
array[1] = 42;                       // <== Changes it
console.log("C2", array.join(", ")); // 1, 42, 3 (changed!)

但是请注意,如果您的代码可以重新定义它以使其可写,那么其他人的代码也可以。

或者,给它一个getter和setter,使其不可配置(因此没有其他人可以重新定义它),并维护一个标志:

const array = [1, 2, 3];
let elementValue = array[1];
let writable = true;
Object.defineProperty(array, "1", {
  get: function() {
    return elementValue;
  },
  set: function(newValue) {
    if (writable) {
      elementValue = newValue;
    }
  },
  enumerable: true,
  configurable: false // Again, emphasis
});

console.log("A", array.join(", ")); // 1, 2, 3
array[1] = 42;
console.log("B", array.join(", ")); // 1, 42, 3 -- it changed
writable = false;
array[1] = 67;
console.log("C", array.join(", ")); // 1, 42, 3 -- didn't change
writable = true;
array[1] = 94;
console.log("D", array.join(", ")); // 1, 94, 3 -- changed

自然,您会隐藏其中的一部分,而只暴露数组本身。