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

Должны ли отрицательные индексы в массивах JavaScript вносить вклад в длину массива?

В javascript я определяю массив вроде этого

var arr = [1,2,3];

также я могу сделать

arr[-1] = 4;

Теперь, если я делаю

arr = undefined;

Я также теряю ссылку на значение в arr [-1].

SO для меня логически кажется, что arr [-1] также является частью arr.

Но когда я делаю следующее (без установки arr на undefined)

arr.length;

Он возвращает 3 не 4;

Итак, моя точка , если массивы могут использоваться с отрицательными индексами, эти отрицательные индексы также должны быть частью их длины **. Я не знаю, может быть, я ошибаюсь, или мне может не хватать понятия о массивах.

4b9b3361

Ответ 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 />");
}