Массив.длина дает неправильную длину
Если у меня есть массив, имеющий объект в качестве значений в индексах, таких как:
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 в качестве вывода. демонстрация
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