Должны ли отрицательные индексы в массивах JavaScript вносить вклад в длину массива?
В javascript я определяю массив вроде этого
var arr = [1,2,3];
также я могу сделать
arr[-1] = 4;
Теперь, если я делаю
arr = undefined;
Я также теряю ссылку на значение в arr [-1].
SO для меня логически кажется, что arr [-1] также является частью arr.
Но когда я делаю следующее (без установки arr на undefined)
arr.length;
Он возвращает 3 не 4;
Итак, моя точка , если массивы могут использоваться с отрицательными индексами, эти отрицательные индексы также должны быть частью их длины **.
Я не знаю, может быть, я ошибаюсь, или мне может не хватать понятия о массивах.
Ответы
Ответ 1
Так что для меня логически кажется, что arr [-1] также является частью arr.
Да, это так, но не так, как вы думаете.
Вы можете назначить произвольные свойства массиву (как и любой другой объект в JavaScript), что вы и делаете, когда вы "индексируете" массив в -1
и присваиваете значение. Поскольку это не элемент массива, а просто произвольное свойство, не следует ожидать, что length
будет учитывать это свойство.
Другими словами, следующий код делает то же самое:
var arr = [1, 2, 3];
arr.cookies = 4;
alert(arr.length) // 3;
Ответ 2
Свойство length
вернет номер один выше самого высокого назначенного "индекса", где "индексы" Array являются целыми числами, большими или равными нулю. Обратите внимание, что JS допускает "разреженные" массивы:
var someArray = [];
someArray[10] = "whatever";
console.log(someArray.length); // "11"
Конечно, если нет элементов, то length
есть 0
. Также обратите внимание, что length
не обновляется, если вы используете delete
для удаления самого высокого элемента.
Но массивы - это объекты, поэтому вы можете назначать свойства с другими произвольными именами свойств, включая отрицательные числа или дроби:
someArray[-1] = "A property";
someArray[3.1415] = "Vaguely Pi";
someArray["test"] = "Whatever";
Обратите внимание, что за кулисами JS преобразует имена свойств в строки, даже когда вы указываете число, подобное -1
. (Положительные целые индексы также становятся строками, если на то пошло.)
Массивные методы, такие как .pop()
, .slice()
и т.д., работают только с нулевыми или высшими целыми "индексами", а не с другими свойствами, поэтому length
является последовательным в этой точке.
Ответ 3
Обратите внимание, что когда вы используете индекс позиции (или 0), значения помещаются внутри массива:
var array = [];
array[0] = "Foo";
array[1] = "Bar";
// Result: ["Foo", "Bar"]
// Length: 2
Это не тот случай, когда вы добавляете неиндексные значения (не 0-9 +):
var array = [];
array[0] = "Foo";
array[1] = "Bar";
array[-1] = "Fizzbuzz"; // Not a proper array index - kill it
// Result: ["Foo", "Bar"]
// Length: 2
Значения помещаются только в массив, когда вы играете по правилам. Когда вы этого не сделаете, они не принимаются. Тем не менее, они принимаются на объект Array, что имеет место практически с чем-либо в JavaScript. Даже если ["Foo", "Bar"]
являются единственными значениями в нашем массиве, мы все равно можем получить доступ к "Fizzbuzz"
:
array[-1]; // "Fizzbuzz"
Но обратите внимание, что это не часть значений массива, так как его "индекс" недопустим. Вместо этого он был добавлен в массив как еще один член. Мы могли бы получить доступ к другим элементам массива таким же образом:
array["pop"]; // function pop() { [native code] }
Обратите внимание, что мы обращаемся к методу pop
в массиве, который сообщает нам, что он содержит собственный код. Мы не обращаемся ни к одному из значений массива с ключом "pop", а скорее к элементу объекта массива. Мы можем еще раз подтвердить это, нажимая на публичные элементы объекта:
for (var prop in array)
console.log(prop, array[prop]);
Из чего вытекает следующее:
0 Foo
1 Bar
-1 Fizzbuzz
Так что опять, это на объекте, но это не в массиве.
Удивительный вопрос! Подумал, что я должен сделать двойной прием.
Ответ 4
Если вы действительно хотите, чтобы отрицательные индексы и другие индексы были включены в длину, создайте сами:
function getExtendedArray() {
var a = [];
Object.defineProperty(a, 'totalLength', {
get : function() { return Object.keys(a).length; }
});
return a;
}
Тогда, например:
var myArray = getExtendedArray();
console.log(myArray.totalLength); // 0
myArray.push("asdf");
myArray[-2] = "some string";
myArray[1.7777] = "other string";
console.log(myArray.totalLength); // 3
Ответ 5
Массивы в JavaScript фактически являются объектами. Они просто прототипируются из конструктора Array.
Индексы массива фактически являются ключами в хэш-карте, и все ключи преобразуются в строки. Вы можете создать любой ключ (т.е. "-1" ), но методы на Array предназначены для работы как массив. Таким образом, length
- это не размер объекта, он скорее гарантированно будет больше, чем самый большой целочисленный индекс. Аналогично, печать arr
будет отображать только значения с целыми ключами >= 0.
Дополнительная информация здесь
Ответ 6
Согласно MDN:
Значение свойства length является целым числом с положительным знаком и значением менее 2 для 32 мощности (232)
В Javascript вы можете установить свойство для любого объекта, который вы создаете.
var array = new Array();
array = [1,2,3];
array["boom"] = "pow";
Таким же образом, когда вы устанавливаете отрицательный индекс, он сохраняет его как свойство в массиве, а не часть индекса.
array[-1] = "property does not add to array length";
Вот почему длина не отражает его, но цикл for..in показывает его.
Ответ 7
Массив - это просто особый вид объектов в JS. Существует специальный синтаксис, который хорош, потому что он позволяет нам эффективно работать с ними. Представьте, как утомительно было бы писать массив букв таким образом:
const array = {{0: 'foo'}, {1: 'bar'}, {2: 'baz}} //etc...
Но объекты все же есть. Так что если вы делаете:
const myArray = [42, 'foo', 'bar', 'baz'];
myArray[-1] = 'I am not here';
myArray['whatever'] = 'Hello World';
Эти нецелочисленные свойства будут присоединены к объекту (который является массивом), но они недоступны нативным методам, таким как Array.length
.
Вы можете предположить, что нативный метод 'length' - это метод получения, который подсчитывает все свойства (и индексы являются свойствами, а значения являются фактическими значениями), которые можно преобразовать в положительное целое число или ноль. Нечто подобное этой псевдо-реализации:
const myArray = {
'-1': 'I am not here', // I have to use apostrophes to avoid syntax error
0: 42,
1: 'foo',
2: 'bar',
3: 'baz',
whatever: 'Hello World',
myLength() {
let counter = 0;
for (let prop in this) {
let toInt = parseInt(prop, 10);
if (!Number.isNaN(toInt) && toInt > -1) {
// If you're not an integer, that not your business! Back off!
counter += 1;
}
}
return counter;
}
}
console.log(myArray.myLength()); // 4
Ответ 8
При использовании неположительных или не числовых индексов массив ведет себя как ассоциативный массив, у которого есть пары ключ-значение.
Чтобы выполнить итерацию по массиву, вы можете использовать
for(var index in myArray) {
document.write( index + " : " + myArray[index] + "<br />");
}