2014-12-19 3 views
9

У меня было немного пробуждение к характеру индексов массива JavaScript в последнее время. Преследуя его, я обнаружил следующее (я работаю с Node.js в режиме интерпретации здесь):Матрицы JavaScript: строковые индексированные элементы

var x=[]; 
x['a']='a'; 
console.log(x); // Yields [ a: 'a' ] 
console.log(x.length); // yields 0 not 1 
x[1]=1; 
console.log(x); // Yields [ , 1, a: 'a' ] 
console.log(x.length); // Yields 2 not 3 (one for empty 0 space, one for the occupied 1 space) 

ли a: 'a' действительно то, что он выглядит - свойство объекта, встроенного в массив - и, таким образом, не является подсчитывается в свойстве массива .length?

+0

Neato. Даже не знал, что это возможно. Имеет смысл, хотя массив является всего лишь объектом. – iambriansreed

ответ

13

В JavaScript массивы являются только объекты с некоторыми специальными свойствами, такими как автоматический length собственности, а также некоторые методы прикреплены (например, sort, pop, join и т.д.). Действительно, a не будет учитываться в вашем массиве, поскольку свойство length массива хранит только количество элементов с именем свойства, которое может быть представлено с 32-битовым положительным целым числом.

И поскольку массивы всегда автоматически определяют каждый пронумерованный элемент до самого высокого элемента с положительным 32-битным именем INT собственности, это эффективно означает length собственность магазинов -выше, чем элемент с самым высоким 32-разрядным целым числом в виде название свойства. Спасибо @Felix Kling за исправление меня об этом в комментариях.

Добавление свойств, таких как a, не запрещено вообще, но вы должны следить за ними, так как это может сбивать с толку при чтении кода.

Там также разница в ходьбе по элементам массива:

пройти через все пронумерованные элементы:

for (var i=0; i<myArray.length; i++) { 
    //do something 
} 

пройти через каждое свойство, не встроенное:

for (var i in myArray) { 
    //do something 
} 

Обратите внимание, что этот цикл также включает в себя все, что включено из Array.prototype, что не является встроенным методом. Итак, если вы должны добавить Array.prototype.sum = function() {/*...*/};, он также будет зациклен.

Чтобы узнать, если объект вы используете действительно массив, а не только объект, можно выполнить следующий тест:

if (Object.prototype.toString.call(myObject) === '[object Array]') { 
    //myObject is an array 
} else if (typeof myObject === 'object') { 
    //myObject is some other kind of object 
} 

См @artem's comment: myObject instanceof Array не всегда может работать правильно.

+3

* «только подсчитывает числовые значения в массиве» * Похоже, что он будет рассматривать элементы самого массива. «Length» всегда 1 + «максимальное» имя свойства, которое может быть преобразовано в 32-битное целое число. –

+0

@FelixKling благодарит за эту коррекцию. Я изменил его соответственно в своем посте. – Joeytje50

+1

'myObject instanceof Array' может возвращать false для некоторых массивов (не уверен в node.js, я помню один случай, когда массив передавался из другого iframe, по-видимому, в некоторых браузерах каждое окно имело свой собственный экземпляр конструктора Array). Всегда полезно делать то, что делает jQuery: в этом случае: Object.prototype.toString.call (myObject) === '[object Array]' ' – artem

2

Да, это правильно. Это работает, потому что почти все в JavaScript - это объект, в том числе массивы и функции, что означает, что вы можете добавить свои собственные свойства строки. Это не ты говоришь, что ты должен сделать это.

Массивы ([]) должны индексироваться с использованием неотрицательных целых чисел. Объекты ({}) должны быть «проиндексированы» с использованием строк.

+0

* Практически все в JavaScript - это объект *. Наверное, вы имеете в виду, что «все значения в JavaScript являются объектами, за исключением примитивов, которые включают числа, строки, нуль и неопределенные». И почему вы не должны помещать строковые свойства в массивы? Это идеальный метод в зависимости от ситуации. –

3

Это правильно, и это хорошая иллюстрация о том, что этот новый массив, который вы создали, на самом деле является просто особым видом объекта. Фактически, typeof [] - 'object'!Установка на нем именованного свойства (которое может быть написано более чисто здесь как x.a = 'a') действительно устанавливает новое свойство обертки объекта вокруг вашего «реального» массива (нумерованные свойства, действительно). Они не влияют на свойство length по той же причине, что и метод Array.isArray.

+0

В массиве нет «обертки объекта». Массив ** является ** объектом. –

+0

Да, это технически верно. Но если вы используете массив, это потому, что вы специально хотите упорядоченный список, и поэтому имеет смысл думать о нем как о другом (и иметь разные применения), чем 'Object'. Тип «Number» также является технически объектом (то есть он наследуется от «Object.prototype»), но действительно бесполезно думать об этом как о одном. Мой термин «обертка объекта» - это просто абстракция, чтобы отличать массив от простого объекта. – OverlappingElvis

Смежные вопросы