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

Это антипаттерн, чтобы задать длину массива в JavaScript?

Неправильно ли использовать код:

var a = [1,2,3,4];
a.length = 2; // 3 and 4 are removed

Есть ли у него достойная поддержка браузера? Удаленные ли значения правильно собирают мусор?

4b9b3361

Ответ 1

Есть ли у него достойная поддержка браузера?

Да. Это имело место с самого первого выпуска ECMAScript:

В частности, всякий раз, когда добавляется свойство, чье имя является индексом массива, если необходимо, изменяется значение длины, которое должно быть больше, чем числовое значение этого индекса массива; и всякий раз свойство length изменяется, каждое свойство, имя которого является индексом массива, значение которого не меньше новая длина автоматически удаляется.

Стандарт ECMA-262, 15.4

В ECMAScript 5 это было перемещено в 15.4.5.2.

Попытка установить свойство length объекта Array на значение, которое численно меньше или равно наибольшему имени числового свойства существующего массива, не индексируемого свойства массива, приведет к тому, что длина будет установлена ​​на числовое значение, которое больше, чем это наибольшее числовое имя свойства.

Стандарт ECMA-262, 15.4.5.2

Все браузеры поддерживают это поведение.


У удаленных значений получается сбор мусора должным образом?

Да. (См. Выше цитаты и 15.4.5.1.)


Является ли это антипаттерном для установки длины массива в Javascript?

Нет, не совсем. В то время как массивы являются "экзотическими объектами" в ES6-talk, настоящая безумно уникальная вещь о массивах - это их индексирование, а не свойство length. Вы можете воспроизвести одно и то же поведение с помощью свойства setter.

Истинно, что свойства seters с не-тонкими эффектами в JS несколько необычны, так как их побочные эффекты могут быть неочевидными. Но поскольку .length был в Javascript с 0-го дня, он должен быть достаточно широко понят.

Если вы хотите использовать альтернативу, используйте .splice():

// a is the array and n is the eventual length

a.length = n;

a.splice(n, a.length - n); // equivalent
a.splice(n, a.length);     // also equivalent

Если бы я почему-то избегал установки .length, это было бы потому, что он мутировал массив, и я предпочитаю неизменное программирование там, где это разумно. Неизбежной альтернативой является .slice().

a.slice(0, n);  // returns a new array with the first n elements

Ответ 2

Массивы - это экзотические объекты.

Экзотический объект - это любая форма объекта, чья семантика свойств каким-либо образом отличается от семантики по умолчанию. 1

Семантика свойств для массивов является специальной, в этом случае изменение длины влияет на фактическое содержимое массива.

Объект Array - это экзотический объект, который дает специальное обращение к ключам свойств индекса массива [...] 2

Также указывается поведение конкретного ключа свойства для этого экзотического объекта массива.

[...] Каждый объект Array имеет свойство length, значение которого всегда является неотрицательным целым числом меньше 2 ^ 32. Значение свойства length численно больше имени каждого собственного свойства, имя которого является индексом массива; когда создается или изменяется собственное свойство объекта Array, другие свойства корректируются по мере необходимости для поддержания этого инварианта [...]

В этом разделе подробно указано, что свойство length является 32-битным целым числом. Он также говорит, что если добавлен индекс массива, длина изменяется. Это подразумевает, что когда используется собственное имя свойства, которое не является индексом, длина не изменяется, а также те имена, которые не являются индексами, считаются численно меньше индексов. Это означает, что если у вас есть массив, а также добавьте ему значение (неявно числовое), как в случае с не 3), то изменение длины для удаления элементов не приведет к удалению значения, связанного со свойством string. Например,

var a = [1,2,3,4];
a.hello = "world";
a.length = 2; // 3 and 4 are removed
console.log(a.hello);//"world"

[...] В частности, всякий раз, когда добавляется собственное свойство, имя которого является индексом массива, значение свойства length изменяется, если необходимо, на одно больше, чем числовое значение этого индекса массива; [...]

В дополнение к усечению расширение также доступно с использованием индекса. Если используется значение индекса (целое число в целом), то длина будет обновлена, чтобы отразить это изменение. Поскольку массивы в JavaScript разрежены (как и в случае отсутствия пробелов), это означает, что добавление значения для большего индекса может сделать массив более крупным.

var a = [1,2,3,4];
a[50] = "hello";
console.log(a.length);//51

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

Наконец, это особый аспект, который поднимает ОП. Когда свойство length массива будет изменено, оно удалит каждый индекс и значение, которое будет численно больше, чем значение новой длины минус 1. В примере OP мы можем ясно видеть, что изменение длины до 2 удаляет значения с индексом 2 и 3, оставив только первые два значения, у которых был индекс 0 и 1.

Алгоритм удаления, упомянутый выше, можно найти в определении ArraySetLength (A, Desc).

  1. б. Пусть deleteSucceeded будет A.[[Delete]](ToString(oldLen)). 3

Что преобразует индекс в строку и использует поведение delete для объектов в индексе. В этот момент все свойство удаляется. Поскольку это внутренне достигает вызова удаления, нет никаких оснований полагать, что это приведет к утечке памяти или даже к тому, что это анти-шаблон, поскольку он явно описан в спецификации языка.

В заключение, имеет ли он достойную поддержку браузера? Да. Убирают ли удаленные значения надлежащий сбор мусора? Да.

Однако, это анти-шаблон? Это можно было бы утверждать в любом случае. То, что он действительно ломает, - это уровень знакомства с языком других, которые будут использовать тот же код, который является хорошим способом сказать, что он может не иметь лучшей читаемости. С другой стороны, поскольку JavaScript использует полосу пропускания или память с каждым используемым символом (следовательно, необходимость в минификсации и связывании), может оказаться полезным использовать этот подход для обрезания массива. Чаще всего, беспокоиться об этом типе minutia будет микро-оптимизации, и использование этого специального свойства следует рассматривать в каждом конкретном случае в контексте общего дизайна связанного кода.

<суб > 1. Тип объекта ECMA 6
<Суб > 2. Экстремальные объекты массива ECMA 6
<Суб > 3. ArraySetLength (A, Desc)ECMA 6

Ответ 3

Как это можно записать https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length (см. здесь) Это должно быть хорошо использовать его таким образом

Вы можете установить свойство length для усечения массива в любое время. Когда вы расширяете массив, изменяя его свойство length, количество фактических элементов не увеличивается; например, если вы установите длину до 3, когда она в настоящее время равна 2, массив все еще содержит только 2 элемента.

Даже пример того, как сократить массив, используя это в Mozilla Developer Network

if (statesUS.length > 50) {
    statesUS.length = 50;
}

Ответ 4

Лучше использовать срез, потому что ваши намерения понятны.

var truncated = a.slice(0,2)

Slice действительно создает новый массив.

Если это проблема для вас, нет ничего плохого в изменении свойства length.

На самом деле это самый быстрый способ усечения и поддерживается во всех браузерах. jsperf

Ответ 5

Является ли это антипаттерном для установки длины массива в JavaScript?

Нет. Было бы нормально установить его для усечения массива.

Есть ли у него достойная поддержка браузера?

Да, см. матрицу совместимости здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length

У удаленных значений получается сбор мусора должным образом?

Да, они должны. Будут ли они на самом деле получить gced - вам нужно будет профилировать код JavaScript, если это является реальной проблемой.

Ответ 6

Этот способ обрезания массива упоминается в JavaScript: Хорошие части, поэтому он не является анти-шаблоном.