Подтвердить что ты не робот

"Замерзание" массивов в Javascript?

Поскольку спецификации ECMA-262 Javascript приобрели метод Object.freeze(), который позволяет создавать объекты, свойства которых не могут быть изменены, добавлены или удалены.

var obj = {'a':1, 'b:2'};
Object.freeze(obj);
Object.isFrozen(obj);       // returns true
obj.a = 10;                 // new assignment has no affect
obj.a;                      // returns 1

Пока все хорошо.

Мне интересно, должен ли freeze() также работать с массивами.

var arr = [1, 2];
Object.freeze(arr);
Object.isFrozen(arr);      // returns true
arr[0] = 10;
arr;                       // returns [10, 2] ... ouch!

Возможно, я ошибаюсь, но у меня создалось впечатление, что массив наследуется от Object.

typeof obj                 // "object"
typeof arr                 // "object"

Любые идеи, указатели, просветы будут высоко оценены.

4b9b3361

Ответ 1

Да, замораживание должно работать для массивов, поведение, которое вы испытываете, явно является ошибкой реализации.

Эта ошибка может быть связана с тем, что объекты массива реализуют собственный [[DefineOwnProperty]] внутренний метод (магия, которая заставляет свойство length работать).

Я только что протестировал его на двух реализациях, и он работает правильно (Chrome 16.0.888 и Firefox Aurora 8.02a).

О вашем втором вопросе, ну, объекты массива, наследуемые от Array.prototype, которые наследуются от Object.prototype, например, вы можете получить доступ к темным методам из Object.prototype непосредственно к объектам массива:

['a'].hasOwnProperty('0'); // true

Но это не связано с тем, как работает typeof, этот оператор вернет 'object' для любого объекта intance, независимо от его вида, и для значения null, о котором люди всегда жаловались.

Остальные возможные возвращаемые значения оператора typeof соответствуют примитивным типам языка: Number, String, Boolean, Symbol и Undefined.

Ответ 2

Вместо того, чтобы заморозить, используйте оператор распространения, чтобы копировать вещи, не изменяя их (если вы используете транспортер, конечно):

const second = {
  ...first,
  test: 20
}