2015-07-05 2 views
17

Я просто хочу понять, как работают массивы JavaScript, но у меня есть сложная проблема.Длина массива и неопределенные индексы

Сначала я создал свой массив:

var arr = []; 

И установить некоторые элементы в нем:

arr[5] = "a thing"; 
arr[2] = undefined; 

Я думал, что я должен иметь массив размером 2, потому что у меня есть только два объекта на 2 конкретных индекса. Так что я тестировал с .length свойства массивов:

document.write(arr.length + "<br>"); 

В результате, интересно, есть 6. Но она должна содержать два элемента. Как его размер может быть 6? Это, вероятно, связано с последним индексом, который я использовал, здесь arr[5] = "a thing";

Затем я попытался петлю над ним:

var size = 0; 
for(var x in arr){ 
size++; 
} 

И переменная size теперь 2. Итак, что я узнал из этого: если Я использую цикл for in, я буду вычислять, сколько в нем свойств, а не его последний индекс.

Но если я попытаюсь установить document.write(arr[4]) (который еще не установлен), он пишет undefined.

Так почему же arr[2] учитывается в for..in циклах, но не arr[4]?

Позвольте мне ответить на мой вопрос: что я думал о typeof undefined == undefined, что удивительно верно. Но это JavaScript, нам нужно играть с ним, используя его собственные правила :)

jsFiddle и сниппет ниже.

var arr = []; 
 

 
arr[5] = "a thing"; 
 
arr[2] = undefined; 
 
document.write(arr.length + "<br>"); 
 

 
var size = 0; 
 
for(var x in arr){ 
 
size++; 
 
} 
 

 
document.write(size + "<br>"); 
 

 
document.write(arr[4] + "<br>");

+0

* длина * свойство всегда ** не менее ** один больше, чем самый большой индекс. Это самонастраивается. – RobG

+4

Важное примечание: * не используйте 'document.write' *, он не делает то, что, по вашему мнению, делает. То, что он делает ** не **, например, это «распечатать некоторые данные». Это чрезвычайно низкоуровневая функция, и у современных JS есть тонны лучших способов сделать то, что в 1998 году нам понадобилось document.write для. –

+0

@ Mike'Pomax'Kamermans, да, я не буду в следующий раз. Все, спасибо за все ответы. –

ответ

11

Примечание: Индексы массивов - это ничего, кроме свойств объектов Array.

Цитирования Relationship between length and numerical properties раздела MDN, в

При установке свойства в массиве JavaScript, когда свойство является допустимым индексом массива и индекс находится вне текущих границ массива, двигатель обновит массив length собственности соответственно.

Цитирование ECMA Сценарий 5 Спецификация Array Objects,

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

Итак, когда вы установите значение по индексу 5, двигатель JavaScript регулирует длину от массива до 6.


Цитирование ECMA Сценарий 5 Спецификация Array Objects,

Имя свойства P (в виде значения String) является индексом массива тогда и только тогда, когда ToString(ToUint32(P)) равно P и ToUint32(P) является не равным 2 -1.

Таким образом, в вашем случае 2 и 4 являются действительными индексами, но только 2 определяются в массиве. Вы можете это подтвердить

arr.hasOwnProperty(2) 

Другие индексы пока не определены в массиве. Таким образом, ваш объект массива называется редким объектом массива.

Зачем считать arr [2] in..in loop и not arr [4] не учитывается?

for..in перечисляет все допустимые перечислимые свойства объекта. В вашем случае, поскольку только 2 является допустимым свойством в массиве, он будет учитываться.

Но когда вы печатаете arr[4], он печатает undefined, потому что JavaScript вернет undefined, если вы попытаетесь получить доступ к свойству, которое не определено в объекте.Например,

console.log({}['name']); 
// undefined 

Аналогично, поскольку 4 пока не определена в arr, undefined возвращается.


В то время как мы на эту тему, вы можете прочитать ответы на эти вопросы, а также,

8

Там разница между свойством, что имеет значение undefined и свойство, которое не существует, показано здесь с помощью in оператора:

var obj = { 
    one: undefined 
}; 

console.log(obj.one === undefined); // true 
console.log(obj.two === undefined); // true 

console.log('one' in obj); // true 
console.log('two' in obj); // false 

При попытке чтобы получить значение свойства, которого не существует, вы все равно получаете undefined, но это не делает его существовавшим.

И наконец, чтобы объяснить поведение, которое вы видите: цикл for in будет только циклически перебирать ключи, где этот ключ in объект (и перечислим).

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

+0

* «длина, между тем, всегда всегда больше, чем самое высокое свойство, которое является индексом». * +1 – christopher

+1

@ Christopher- «* ... всегда ** хотя бы ** еще один ... *". – RobG

0

Назначение задает свойство массива, так что когда вы выполняете цикл стиля for var i in, вы видите только те свойства, которые были установлены (даже если вы установили их неопределенными). Когда вы назначаете новое свойство integery, такое как arr[6], массив изменяет длину массива равным 7.Память, лежащая в основе массива, может или не может быть перераспределена соответствующим образом, но она будет доступна вам, когда вы ее используете, - если ваша система не находится в памяти.

Отредактировано в соответствии с комментарием RobG о том, что говорит ECMA-262.

+0

@ RobG достаточно справедливо. Я отредактирую ответ. – Catalyst

2

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

Результат интересный, это 6. Но он должен содержать два данных, как его размер может составлять 6? Вероятно, это связано с последним индексом, который I используется здесь arr [5] = «вещь»;

Это приводит к 6 потому length всегда 1 выше, чем самый высокий показатель, даже если есть на самом деле меньше элементов в массиве.

o почему arr [2] учитывается для .. в петле и не arr [4] не учитывается?

, потому что когда вы делаете:

arr[2] = undefined;

Вы на самом деле добавить ключ с именем 2 к объекту массива. В результате значение arr[2] засчитывается в цикле for in, а a[4] игнорируется.

3

Чтобы удалить undefined значения из массива, попробуйте используя .filter()

var arr = []; 
 
arr[5] = "a thing"; 
 
arr[2] = undefined; 
 
arr = arr.filter(Boolean); 
 
document.write(arr.length);

3

Это все сводится к идее о том, как пространство с помощью машин. Давайте начнем с простейшей идеи:

var arr =[]; 

Это, в свою очередь, создает местоположение, где вы можете хранить информацию.Как Pomax «@ Mike» Kamermans отметил: Это место специальный Javascript объект, который в свою очередь, функционирует как совокупность ключей и значений, например, так:

arr[key] = value; 

Переходим по коду:

arr[5] = "a thing"; 

Теперь машина понимание того, что вы создаете что-то в (дает значение к) 6-ю позицию/пятые ключ (как первая позиция массива является 0). Таким образом, вы завершаете с чем-то, что выглядит следующим образом:

arr[,,,,,"a thing"]; 

Эти запятые представляют собой пустые позиции (elisions, как @RobG указывал) в массиве.

То же самое происходит, когда вы объявляете:

arr[2] = undefined; 
arr[,,undefined,,,"a thing"]; 

Итак, когда вы перебор внутри массива с помощью «для вара в» вы проверяете для каждого из пространств в этом массиве, которые заселены, так что в свою очередь 2.

как разница, когда вы проверить на длину массива, вы хотите, чтобы увидеть сколько пространства для хранения информации существуют внутри массива, который, в свою очередь 6.

Наконец, javascript интерпретирует пустую комнату в массиве как неопознанные значения, что является причиной, по которой arr [4] выводится как таковой.

Надеюсь, что ответил на ваш вопрос.

+0

Это просто не относится к JS. JS-массив - это просто объект JS (тот, который вы знаете как '{}'), но с некоторыми специальными функциями итерации и специальной обработкой ключа-valye.Установка 'arr = []', а затем 'arr [5] =« something »' НЕ создает что-то на «шестой позиции», он просто связывает свойство «что-то» с ключом объекта «5». Массив 'length' будет сообщать 6, но сам массив будет содержать элемент * 1 *. –

+0

"* пустые позиции *" в литературе массива [* elisions *] (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-initializer) и представлены запятые: '[,,,,," вещь "]'. Такие члены, как говорят, * исключены *, они не существуют и возвращаются * неопределенными * при доступе к чтению. – RobG

+0

@ Mike'Pomax'Kamermans не может не согласиться с тем, что вы говорите, в том смысле, что он семантически корректен для javascript. Вы правы, у массивов есть ключи и значения, а не позиции. Я отредактирую свой ответ. Кроме того, RobG я пытался объяснить концепцию самым простым способом, также понял, подчеркивает, где проще использовать в качестве представления. В любом случае я не могу не согласиться с вами в семантике. –

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