Нуль занимает память в javascript?

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

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, и кто-то даже упомянул о реализации связанных списков. Я не думаю, что мне нужно реализовывать связанный список, так как я не очень часто добавляю или удаляю элементы.


person Radu    schedule 27.06.2011    source источник


Ответы (4)


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

Назначая '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.
person codelahoma    schedule 27.06.2011
comment
Это тоже было бы моим предложением. - person Šime Vidas; 28.06.2011
comment
Обратите внимание, что установка свойства в значение undefined на самом деле не означает, что оно не занимает места: свойство может существовать и иметь явное значение undefined, например, var x = {a: undefined}; alert(x.a); alert(x.b); alert(a in x); alert(b in x);. Если вы хотите удалить свойство, используйте delete. - person gsnedders; 28.06.2011
comment
Спасибо, что подняли этот вопрос. Я хотел упомянуть об этом и отредактирую ответ, чтобы включить его. - person codelahoma; 28.06.2011
comment
в приложенной статье автор говорит, что это заблуждение, что использование удаления очищает связанную память (может быть собрана сборщиком мусора) smashingmagazine.com/2012/11/ - person Harshit Gupta; 17.10.2016

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

person Bohdan    schedule 27.06.2011

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

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

person Arthur P    schedule 27.06.2011
comment
Спецификация требует, чтобы undefined возвращалась внутренней функцией GetOwnProperty объекта, если объект не имеет свойства с указанным именем. В то время как фактическое undefined значение, которое вы бы использовали, скажем, в условном выражении, может использовать память, неопределенные свойства (это то, чем является элемент массива, которому никогда не присваивалось значение). ) не делайте. - person codelahoma; 28.06.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 = [] и динамически изменил его размер по мере необходимости - с простой точки зрения установки и получения значений по определенным индексам, это точно так же.

person nrabinowitz    schedule 27.06.2011