Действительно ли массивы JavaScript реализованы как массивы?

Разница между JavaScript Array и Object не очень велика. На самом деле кажется, что Array в основном добавляет поле length, поэтому вы можете использовать как Arrays, так и Objects как числовые массивы:

var ar = new Array();
ar[0] = "foo";
ar["bar"] = "foo";

var ob = new Object();
ob[0] = "foo";
ob["bar"] = "foo";

assert(ar[0] == ob[0] == ar["0"] == ob["0"] == ar.bar == ob.bar); // Should be true.

Итак, мои вопросы: в популярных движках JavaScript (V8, JavaScriptCore, SpiderMonkey и т. д.), как это обрабатывается? Очевидно, мы не хотим, чтобы наши массивы фактически хранились в виде хэш-карт со значениями ключей! Как мы можем быть уверены, что наши данные хранятся в виде фактического массива?

Насколько я вижу, есть несколько подходов, которые могут использовать двигатели:

  1. Array реализован точно так же, как Object — как ассоциативный массив со строковыми ключами.
  2. Array — это особый случай, с массивом, подобным std::vector, поддерживающим числовые клавиши, и некоторой эвристикой плотности, чтобы предотвратить безумное использование памяти, если вы делаете ar[100000000] = 0;
  3. Array совпадает с Object, и все объекты получают эвристику, чтобы увидеть, будет ли использование массива иметь больше смысла.
  4. Что-то безумно сложное, до чего я не додумался.

На самом деле это было бы проще, если бы существовал правильный тип массива (cough WebGL типизированные массивы кашель).


person Timmmm    schedule 10.02.2012    source источник
comment
Эта статья немного устарела и не объясняет явно реализация. Тем не менее, он выполняет подробные измерения производительности и делает выводы о возможных реализациях.   -  person Matthew Flaschen    schedule 10.02.2012
comment
Массив — это не просто карта с добавленным свойством length. Если бы это было так, то смещение или несмещение нарушило бы индексацию (т. е. сместило бы значение из массива, и оно по-прежнему начинается с индекса 0, а не 1). Так что по крайней мере немного больше происходит. (Конечно, это не обязательно говорит о реализации)   -  person Flambino    schedule 11.02.2012
comment
Почему вы ожидаете, что r[0] == ob[0] == ar["0"] == ob["0"] == ar.bar == ob.bar будет правдой? 'a' == 'a' == 'a' является ложным, потому что оно оценивается как true == 'a', которое оценивается как false.   -  person Mike Samuel    schedule 11.02.2012
comment
@ Фламбино, это неправда. shift реализован как общий метод, а не специфичный для массива. Он будет отлично работать с обычным объектом. Сдвиг работает, потому что он захватывает первое значение, затем перебирает все значения, присваивая значение left, и, наконец, удаляет последний элемент и устанавливает длину.   -  person Mike Samuel    schedule 11.02.2012
comment
@Flambino, попробуйте запустить var a = { 0: 0, 1: 1, length: 2 }; Array.prototype.shift.apply(a); alert(JSON.stringify(a)). Вы должны надежно получить {"0":1,"length":1}.   -  person Mike Samuel    schedule 11.02.2012
comment
@MikeSamuel Сэр, я исправлен. Я никогда не думал попробовать это на объекте, отличном от массива. Однако мне должно было прийти в голову, поскольку я достаточно часто использовал slice для arguments объектов. Интересно   -  person Flambino    schedule 11.02.2012


Ответы (2)


В SpiderMonkey массивы реализованы в основном как массивы C jsvals. Они называются «плотными массивами». Однако, если вы начнете делать с ними вещи, не похожие на массивы — например, обращаться с ними как с объектами — их реализация изменится на что-то очень похожее на объекты.

Мораль этой истории: когда вам нужен массив, используйте массив. Когда вам нужен объект, используйте объект.

О, jsval — это разновидность вариативного типа, который может представлять любое возможное значение JavaScript в 64-битном типе C.

person Wes    schedule 18.02.2012

В V8 и Carakan (и, предположительно, в Chakra) все (не хостовые) объекты (и те, которые являются массивами, и те, которые не являются) со свойствами, чьи имена являются индексами массива (как определено в ES5), хранятся либо как плотный массив (массив C, содержащий некоторую оболочку значений) или разреженный массив (который реализован как двоичное дерево поиска).

Унифицированное представление объекта проявляется в том, что оно влияет на порядок перечисления: с объектом, SpiderMonkey и SquirrelFish дают все свойства в порядке вставки; а с массивом они вообще (по крайней мере, в SM есть особые случаи!) сначала индексируют массив, а затем все остальные свойства в порядке вставки. V8, Carakan и Chakra всегда сначала дают индексы массива, а затем все остальные свойства в порядке вставки, независимо от типа объекта.

person gsnedders    schedule 11.07.2012
comment
Спасибо за информацию, а источник какой? - person Klesun; 02.02.2021