2011-06-27 3 views
21

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

ответ

14

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

Путем присвоения '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. 
+0

Это тоже мое предложение. –

+0

Обратите внимание, что просто установка свойства в undefined фактически не заставляет его не занимать места: свойство может существовать и иметь явное значение «undefined», например, «var x = {a: undefined}; оповещения (x.a); оповещения (x.b); alert (a в x); alert (b in x); '. Если вы хотите удалить свойство, используйте 'delete'. – gsnedders

+0

Спасибо, что принесли это. Я хотел бы упомянуть об этом и отредактировать ответ. – codelahoma

1

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

1

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

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

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

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

  • Он устанавливает 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, ваша функция будет только для для индексов, которые вы явно указали на значение post-construction.

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

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

и:

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

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

1

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

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

+2

Спецификация требует, чтобы 'undefined' быть возвращена внутренней' функции GetOwnProperty' объекта, если объект не имеет свойства по указанному имя. Хотя фактическое значение 'undefined' * *, которое вы используете, скажем, в условном выражении, может использовать память, * undefined properties * (это то, что элемент Array, которому никогда не назначалось значение), нет. – codelahoma

Смежные вопросы