Занимает ли null память в javascript? - PullRequest
23 голосов
/ 28 июня 2011

У меня следующая ситуация:

var large = [a,b,c,d,e,f,g,h,i];
var small = [a2, b2, c2, null, null, null, null, null, null, i2];

, где каждый элемент обоих массивов является объектом.

Маленький массив содержит информацию, относящуюся к большему, но некаждому элементу large требуется связанный элемент в small, поэтому я установил его на null.Тем не менее, мне все еще нужно сохранять индексы такими же, чтобы я мог делать такие вещи, как large[16].id + ': ' + small[16].description.Означает ли тот факт, что у меня есть массив, значение которого в основном равно null, приводит к увеличению использования памяти?

Мой вопрос заключается в том, лучше ли мне делать что-то вроде small = [a2,b2,c2,i2] и устанавливатьиндексы в свойствах типа a2.index = 0; b2.index = 1 и т. д.

Я также натолкнулся на предложение использовать undefined вместо этого, и кто-то даже упомянул реализацию связанных списков.Я не думаю, что мне нужно реализовывать связанный список, так как я не очень часто добавляю или удаляю элементы.

Ответы [ 4 ]

16 голосов
/ 28 июня 2011

Массивы на самом деле являются объектами со специальной обработкой свойств с именами, которые являются индексами массивов.

Назначая 'null', вы создаете каждое свойство, которое будет использовать ненулевой объем памяти и, как уже упоминалось, замедляет поиск.

Вместо этого вы можете исключить несуществующие элементы, что приведет к разреженному массиву:

var small = [a2, b2, c2,,,,,,, i2];
// small == [a2, b2, c2,undefined,undefined,undefined,undefined,undefined,undefined, i2]

Редактировать Обратите внимание, что undefined занимает пробел, если вы явно назначаете его элементу массива (или любой переменной). Чтобы восстановить память в этом случае, вам нужно явно delete элемент. Стиль инициализации, показанный в моем примере кода, никогда не присваивает что-либо исключенным элементам, поэтому они вообще не существуют. Это может быть подтверждено проверкой существования этих элементов в качестве свойств объекта массива:

// continued from above
small.hasOwnProperty('3'); // returns false

small[3] = undefined;
small.hasOwnProperty('3'); // now returns true because the property exists

delete small[3];
small.hasOwnProperty('3'); // returns false again

alert(small.length); // alerts '10', showing that the array itself is still intact.
1 голос
/ 28 июня 2011

Я не могу полностью ответить на ваш вопрос, потому что я не уверен, занимает ли null столько места, сколько явно указано для undefined.Но я считаю, что стандартный способ сделать это - использовать конструктор Array:

var large = [1,2,3,4,5,6,7];
var small = new Array(large.length);
small.length; // 7
small[0]; // undefined

Я считаю, что для этого используется меньше памяти, чем для явного задания значений undefined, хотя эффект тот же.Я использовал это для разреженного массива с 250 000+ индексами и не испытывал проблем с памятью (при использовании Google Chrome).

Редактировать: (после игры и немного поигратьдополнительные исследования) Многим людям не нравится конструктор new Array() по многим причинам (см., например, это обсуждение ).Но я думаю, что у больших разреженных массивов есть несколько преимуществ:

  • Он правильно устанавливает свойство length.Если вам нужна длина массива, соответствующая вашему большому массиву, вы не сможете сделать это иначе, если не установите ее явно (small.length = large.length) или не поместите что-то неопределенное в конец (small[large.length-1] = undefined).

  • Он не устанавливает ключи для пустых индексов, поэтому я считаю, что он использует меньше памяти.Если у вас есть массив a = [null,null,null] или a = [undefined,undefined,undefined], каждый из этих массивов имеет три индекса, и если вы используете a.map или a.forEach, ваша функция будет вызываться для каждого индекса.Если вы используете a = new Array(3), а затем вызываете a.forEach, ваша функция будет только вызываться для индексов, для которых вы явно установили значение после построения.

Но , похоже, нет большой разницы в производительности между:

var a = new Array(2000); 
a[2000] = 1;

и:

var = [];
a[2000] = 1;

, которые также дает вам массив длиной 2000 с только одним определенным индексом.Поэтому, если вам все равно, соответствует ли length из small length из large, я просто использовал бы var a = [] и изменил бы его динамическое изменение по мере необходимости - с простой точки зрения установки и получениязначения по конкретным показателям, это точно так же.

1 голос
/ 28 июня 2011

Null будет использовать память только для размера слова 'NULL' (в терминах интерпретатора), но поиск замедлится из-за массива, перегруженного объектами, которые не попадут в результат поиска, а JS сделаетнет способа оптимизировать это.Вам лучше использовать массив объектов, и каждый объект должен сохранять значение и индекс.

Использование undefined также сложно.С точки зрения интерпретации и размера скрипта это увеличит объем памяти, но это не является частью спецификации, которая указывает, должен ли undefined потреблять память и сколько, так что это зависит от браузера, его возможностей для сбора мусора, потребления кучи памятии т.д. Лучший способ - попробовать, наверное.Запустите относительно большой массив значений NULL и неопределенных в Chrome, сделайте снимок кучи и сравните.

1 голос
/ 28 июня 2011

Почему бы просто не положить мелкие предметы в большие [2]. Маленькие? В любом случае, вам обычно не нужно беспокоиться о потреблении памяти в javascript, но все же лучше оставить неиспользуемые позиции в небольшом неопределенном (что-то иное, чем установить их в неопределенное!), Так что движок javascript может принять решение о переключении разбирать массив (представленный хеш-таблицей вместо массива).

...