Как массивы в JavaScript представлены в физической памяти?
насколько я понимаю, я могу хранить смешанные данные в массиве JavaScript, а также изменять любой элемент массива на какой-либо другой тип. Как интерпретатор отслеживает, какое место в физической памяти занимает какой-либо элемент. Также как предотвратить перезапись данных в следующем элементе, если я изменю элемент на более крупный тип данных.
Я предполагаю, что массивы хранят только ссылки на фактические объекты, а примитивы завернуты за кулисы при размещении в матрицы.
предполагая, что это так, Если у меня есть другой дескриптор примитивной переменной и изменение значения, хранящегося в массиве, поддерживается синхронность?
Я знаю, что, вероятно, уже ответил на свой вопрос, но я не знаю точно, и я не могу найти никакой информации по этому вопросу.
2 ответов
обычно массивы выделяют непрерывный блок памяти фиксированной длины. Однако в Javascript массивы являются типами объектов со специальными конструкторами и методами доступа.
что означает, утверждение типа:
var arr = new Array(100000);
не выделяет никакой памяти! Фактически, он просто устанавливает значение свойства length в массиве. Когда вы создаете массив, вам не нужно объявлять размер, поскольку они растут автоматически. Итак, вы должны использовать это вместо этого:
var arr = [];
массивы в Javascript разрежены, что означает, что не все элементы в массиве могут содержать данные. Другими словами, в массиве существуют только элементы, которые фактически содержат данные. Это уменьшает объем памяти, используемой массивом. Значения расположены по ключу, а не по смещению. Они просто метод удобства и не предназначены для использования для комплексного численного анализа.
массивы в Javascript не набираются, поэтому значение элемента может быть объектом, строкой, числом, логическим значением, функцией или массивом. Основное различие между массивом и объектом-свойство length, которое имеет значение больше, чем самый большой целочисленный ключ в массиве.
например:
вы можете создать пустой массив и добавить два элемента с индексом 0 и индексом 99. Длина будет равна 100, но количество элементов в массиве будет равно 2.
var arr = [];
arr[0] = 0;
arr[99] = {name: "John"};
console.log(arr.length); // prints 100
arr; // prints something like [0, undefined × 98, Object { name: "John"}]
чтобы ответить на ваши вопросы напрямую:
Q. насколько я понимаю, я могу хранить смешанные данные в массиве JavaScript, а также изменять любой элемент в массиве на какой-либо другой тип. Как интерпретатор отслеживает, в каком месте физической памяти находится какой-либо элемент? Кроме того, как предотвратить перезапись данных в следующем элементе, если я изменю элемент на более крупный тип данных?
A. вы, вероятно, уже знаете это, если вы читали мои комментарии выше. В Javascript array - это тип объекта Hashtable, поэтому интерпретатору не нужно отслеживать физическую память, а изменение значения элемента не влияет на другие элементы, поскольку они не хранятся в непрерывном блоке памяти.
--
Q. я предполагаю, что массивы хранят только ссылки на фактические объекты, а примитивы завернуты за кулисы при размещении в массивах. Предполагая, что это так, если у меня есть другой дескриптор примитивной переменной и изменение значения, хранящегося в массиве, поддерживается синхронность?
A. нет, примитивы не завернуты. Изменение примитива, назначенного массиву, не изменит значение в массиве, поскольку они хранятся по значению. Объекты, с другой стороны, хранятся по ссылке, поэтому изменение значения объектов будет отражать это изменение в этом массиве.
вот пример, который вы можете попробовать:
var arr = [];
var obj = { name: "John" };
var isBool = true;
arr.push(obj);
arr[1] = isBool;
console.log(arr[0]); // print obj.name
console.log(arr[1]); // print true
obj.age = 40; // add age to obj
isBool = false; // change value for isBool
console.log(arr[0]); // value here will contain age
console.log(arr[1]); // value here will still be true
кроме того, обратите внимание, что когда вы инициализируйте массив двумя способами, он имеет другое поведение:
var arr = new Array(100);
console.log(arr.length); // prints 100
console.log(arr); // prints []
var arr2 = new Array(100, 200);
console.log(arr2.length); // prints 2
console.log(arr2); // prints [100, 200]
если вы хотите использовать массивы Javascript в качестве смежных блоков памяти, вы должны изучить использование TypedArray. TypedArray позволяет выделить блок памяти в виде массива байтов и более эффективно получить доступ к необработанным двоичным данным.
вы можете узнать больше о тонкостях Javascript, прочитав ECMA-262 spec (ver 5.1).
вот немного пищи для размышлений. Я сделал a jsperf для тестирования простой оптимизации массива что некоторые движки JavaScript реализовать.
тестовый случай создает два массива с миллионом элементов каждый. The a
массив содержит только цифрами;b
массив содержит те же числа, за исключением первого элемента, который является объектом:
var a = [ 0 ], b = [ { valueOf: function() { return 0; } } ];
for( var i = 1; i < 1000000; ++i ) {
a[i] = b[i] = i;
}
The valueOf
свойства объекта в первом элементе b
возвращает массив 0
так арифметика будет такой же, как и первый массив.
затем два теста просто суммировать все значения для двух массивов.
быстрый массива:
var x = 0;
for( var i = 0; i < 1000000; ++i ) {
x += a[i];
}
медленно массива:
var x = 0;
for( var i = 0; i < 1000000; ++i ) {
x += b[i];
}
как вы можете видеть из результатов теста в jsperf, в Chrome числовой массив примерно в 5 раз быстрее, в Firefox числовой массив примерно в 10 раз быстрее, а в IE примерно в 2 раза быстрее.
это напрямую не раскрывает внутренние структуры, используемые для массив, но это дает довольно хороший признак того, что они сильно отличаются друг от друга.