Массив.длина дает неправильную длину



Если у меня есть массив, имеющий объект в качестве значений в индексах, таких как:



var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
alert(a.length); // outputs 91


Я нашел обходной путь, чтобы получить фактическую длину:



function getLength(arr) {
return Object.keys(arr).length;
}
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
alert(getLength(a));


Но почему JS дает неправильную длину, когда объекты хранятся в случайных индексах? он просто добавляет 1 к самому большому индексу, найденному в массиве. Как и в приведенном выше примере, 90 был самым большим индексом. Он просто добавляет 1 и дает 91 в качестве вывода. демонстрация

454   4  

4 ответов:

Это потому, что length дает вам следующий index, доступный в массиве.

Документы

ArrayLength

Если единственным аргументом, переданным конструктору массива, является целое число от 0 до 2^32-1 (включительно), то возвращается новый массив JavaScript с длиной, равной этому числу.

Спецификации ECMA

Потому что вы не вставили ни одного элемента в другие ключи, кроме 21, 90, 13, все остальные индексы содержит undefined. демо-версия

Чтобы получить фактическое число элементов в массиве:

var a = [];
a[21] = {};
a[90] = {};
a[13] = {};

var len = 0;

for (var i = 0; i < a.length; i++) {
  if (a[i] !== undefined) {
    len++;
  }
}
document.write(len);

Сокращенная версия

var a = [];
a[21] = {};
a[90] = {};
a[13] = {};


for (var i = 0, len = 0; i < a.length; i++, a[i] !== undefined && len++);


document.write(len);

Демо-версия

EDIT

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

Как вы упомянули в вопросе, Object.keys(arr).length является ли лучшим решением в в этом случае, учитывая, что у вас нет никаких свойств, добавленных в этот массив. В противном случае, length не будет тем, что вы могли бы ожидать.(Спасибо @RobG)

Потому что это поведение массива.длина, как описано в спецификацииECMAScript .

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

Итак, Массив.длина - это всегда индекс последнего элемента + 1.

Массив в JavaScript-это простая нулевая структура. array.length возвращает n + 1, где n - максимальный индекс в массиве.

Вот как это работает - когда вы назначаете 90 ' - й элемент и длина этого массива меньше 90, он расширяет массив до 90 и устанавливает значение 90-го элемента. Все пропущенные значения интерпретируются как null.

Если вы попробуете следующий код:

var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
console.log(JSON.stringify(a));

Вы получите следующий JSON:

[null,null,null,null,null,null,null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{}]

Более того, array.length является не только значение для чтения.
Если вы зададите length значение меньше , чем текущее, то размер массива будет изменен:

 var arr = [1,2,3,4,5];
 arr.length = 3;
 console.log(JSON.stringify(arr));
 // [1,2,3]

Если вы зададите length значение больше , чем текущее, то массив также будет расширен:

 var arr = [1,2,3];
 arr.length = 5;
 console.log(JSON.stringify(arr));
 // [1,2,3,null,null]

В случае необходимости присвоения таких значений можно использовать объекты JS.
Вы можете использовать их в качестве ассоциативного массива и назначать любые пары ключ-значение.

var a = {};
a[21] = 'a';
a[90] = 'b';
a[13] = 'c';
a['stringkey'] = 'd';
a.stringparam = 'e'; // btw, a['stringkey'] and a.stringkey is the same

console.log(JSON.stringify(a)); 
// returns {"13":"c","21":"a","90":"b","stringkey":"d","stringparam":"e"}

console.log(Object.keys(a).length);
// returns 5

Это потому, что у вас есть[90] как самый большой индекс, поэтому индекс, начиная с 0 до 90, становится 91 в длину.

И где вы не передали значения, такие как [80] и т. д. javascript будет хранить их как отверстие, то есть, например, [1, , 3, , ,90] , где используются запятые, указывает на отверстие в массиве.

Если вы попытаетесь получить доступ к этим значениям, то вы получите undefined.

Comments

    Ничего не найдено.