Как работает JavaScript []?

Я пишу интерпретатор JavaScript для встроенных устройств с ограниченными ресурсами (http://www.espruino.com), и каждый раз, когда я думаю, что у меня есть реализовал некоторый бит JavaScript правильно, я понимаю, что ошибаюсь.

Теперь мой вопрос о []. Как бы вы реализовали один из самых простых битов JavaScript правильно?

Я просмотрел спецификацию JavaScript и, возможно, я не нашел нужный бит, но я не могу найти полезный ответ.

Ранее я предполагал, что у вас фактически есть две "карты" - одна для целых чисел и одна для строк. И длина массива была значением самого высокого целого числа плюс один. Однако это кажется неправильным, согласно jsconsole на chrome:

var a = [];
a[5] = 42;
a["5"]; // 42
a.length; // 6

но также:

var a = [];
a["5"] = 42;
a[5]; // 42
a.length; // 6

Итак... great - все преобразуется в строку, а строка с наивысшей оценкой, представляющая целое число, используется (плюс одна) для получения длины? Неправильно.

var a = [];
a["05"] = 42;
a.length; // 0

"05" - действительное целое число - даже в Octal. Итак, почему это не влияет на длину?

Вам нужно преобразовать строку в целое число, а затем проверить, что при преобразовании обратно в строку оно соответствует?

Есть ли у кого-нибудь ссылка на точный алгоритм, используемый для хранения и получения элементов в массиве или объекте? Похоже, это должно быть очень просто, но похоже, что на самом деле это не так!

Ответ 1

Как сказано в спецификациях, и было отмечено другими:

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

Это объясняет, почему в вашем сценарии "5" рассматривается индекс массива, а "05" - нет:

console.log("5" === String("5" >>> 0));
// true, "5" is equal to "5", so it an index

console.log("05" === String("05" >>> 0));
// false, "05" is not equal to "5", so it not an index

Примечание: "Нулевой нулевой сдвиг" - это самый короткий путь в JS, чтобы заменить ToUint32, сдвинув число на ноль.

Ответ 2

См. MDN

Можно также указать индексы массива JavaScript (например, лет [ "2" ] вместо лет [2]), хотя это и не нужно. 2 в лет [2] в конечном итоге принуждается к строке с помощью JavaScript во всяком случае, через неявное преобразование toString. Это для по этой причине, что "2" и "02" относятся к двум различным слотам объект years и следующий пример: true:

console.log(years["2"] != years["02"]);

Итак, с a["5"] вы получаете доступ к массиву, а a["05"] задает свойство объекта массива.

Ответ 3

Массивы - это просто объекты. Это означает, что они могут иметь дополнительные свойства, которые не считаются элементами массива.

Если аргумент квадратной скобки является целым числом, он использует его для выполнения присвоения массиву. В противном случае он обрабатывает его как строку и сохраняет его как свойство объекта массива.

Редактировать на основе комментариев delnan и комментариев DCoder, так JavaScript определяет, является ли он подходящим индексом для массива (только для свойства): http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

Ответ 4

Массивы также являются объектами.

Сделав это

a["05"] = 5;

Вы делаете то же самое, что:

a.05 = 5;

Однако, приведенное выше приведет к синтаксической ошибке, поскольку свойство, указанное после того, как точка не может начинаться с числа.

Итак, если вы это сделаете:

a = [];
a["05"] = 5;

у вас все еще есть пустой массив, но свойство a с именем 05 имеет значение 5.

Число x - это индекс массива, если и только если ToString(ToUint32(x)) равно x (поэтому в случае "05" это требование не выполняется).