Как работает 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"
это требование не выполняется).