JavaScript новое ключевое слово и управление памятью - PullRequest
21 голосов
/ 08 марта 2010

Исходя из C ++, мне трудно понять, что каждый раз, когда я звоню new, я звоню delete. В JavaScript я иногда вызываю new в своем коде, но (надеясь), что функция сбора мусора в браузере позаботится обо мне.

Мне это не нравится - есть ли метод delete в JavaScript и чем я его использую, отличается от C ++?

Спасибо.

Ответы [ 11 ]

24 голосов
/ 08 марта 2010
var component = new Component();
component = null; // delete this at next garbage collection
13 голосов
/ 08 марта 2010

Между прочим, ключевое слово "new" на самом деле не обязательно в javascript и не имеет (напрямую) никакого отношения к выделению памяти. Все, что «new» делает, это передает новый пустой объект с именем «this» (this = {}) в качестве скрытого аргумента функции.

var MyClass = function(){
    // fresh empty object "this" gets passed to function
    // when you use the "new" keyword 
    this.method = function(){}
}

var myInstance = new MyClass();

Javascript может стать немного шероховатым из-за вложенных замыканий и множества переменных «this», плавающих в разных областях. Я предпочитаю делать это так:

var MyNoNewClass = function(){
    // I find this more explicit and less confusing
    var self = {}
    self.method = function(){}
    return self;
}

var myNoNewInstance = MyNoNewClass()
5 голосов
/ 08 марта 2010

Ссылка на всю память JavaScript, но не в традиционном смысле.Память ссылается не по адресу памяти, а по строке.В этом коде:

var x = new someObj();

На этот объект ссылается строка "x" с этой точки вперед.x не является указателем на некоторую память в куче в этой точке.Если вы присвоили свойство xa, то:

x.someProp = 42;

Тогда someProp - это строка в памяти, ссылающаяся на значение 42. Следовательно, это позволяет использовать запись массива для доступа к нему по строковому представлению:

x["someProp"]++;

Именно поэтому переменные могут содержать любое значение, поскольку им не нужен размер.

Память собирается в JavaScript, по сути, когда на нее не ссылаются строки (имена переменных или свойств).Этот объект будет собран, когда x присваивается любое другое значение.Вы можете установить его на null, undefined или что-то еще, и эта память будет собираться.

То есть она будет собираться, когда браузер или любой другой движок JavaScript обойдут ее.

Удалить только удаляет свойства из объектов.После этого попытка получить доступ к этому свойству вернет undefined.По большей части следующие 2 строки кода эквивалентны:

x["someProp"] = undefined;
delete x.someProp;

Редактировать: Хорошо, внутренне эти две строки не совпадают.Оператор удаления удалит ссылку «someProp» из памяти, а установка неопределенного значения - нет.Я думаю.Я не могу найти ничего в спецификациях о том, чтобы установить переменную или свойство в undefined, но я не думаю, что это делает что-то особенное.

Важно отметить, что вы не сможетеудалите свойства, для которых установлен определенный флаг, но вы можете установить для них значение null или undefined (если они не упакованы установщиком и даже позволяют этому происходить).

3 голосов
/ 08 марта 2010

Вне контекста (браузера) javascript полностью способен восстанавливать память посредством сборки мусора. Возвращаясь к реальности, сборка мусора в сочетании с моделью DOM может привести к утечке памяти.

Вот одна статья http://www.ibm.com/developerworks/web/library/wa-memleak/ вы можете найти более подробную информацию об этом

2 голосов
/ 25 ноября 2013

Чтобы избежать утечек памяти

  1. Убедитесь, что вы удалили все обработчики событий, поэтому, если вы добавляете как обработчик событий мыши, убедитесь, что вы удалили его, когда закончите
  2. если вы добавляете элементы в DOM, удалите их, когда закончите
  3. если у вас есть объект, который указывает на другой объект, удалите ссылку, когда объект будет завершен.
  4. когда вы закончите с любым объектом, установите его на нуль.

удаляет просто удалить свойство из объекта.

1 голос
/ 09 марта 2010

new создает объекты из конструктора. delete удаляет свойства из объекта. Это две очень разные вещи.

Вам не нужно удалять созданные вами объекты. GC позаботится об этом.

delete o.fu отличается от o.fu = undefined. Попробуйте это:

var o = {};
alert(o.hasOwnProperty('fu')); // -> false
o.fu = undefined;
alert(o.hasOwnProperty('fu')); // -> true
delete o.fu;
alert(o.hasOwnProperty('fu')); // -> false
1 голос
/ 08 марта 2010

Из MDC :

Оператор delete удаляет свойство объекта или элемента по указанному индексу в массиве.

Оператор удаления, на мой взгляд, полезен только тогда, когда вы хотите удалить свойство из объекта. Но поскольку могут быть другие ссылки на свойство, на которое оно ссылалось, оно не будет действительно GCed. Если вы хотите, чтобы что-то было GCed, вам нужно удалить все указатели, указывающие на это, а также освободить замыкания, содержащие ссылки на него ( больше информации по теме ).

1 голос
/ 08 марта 2010

Не используйте delete в JavaScript, если вы не удаляете обработчики событий. Даже в этом случае мы делаем это только потому, что в более старых версиях IE с этой практикой связана утечка памяти Дуглас Крокфорд объясняет это довольно хорошо. В его случае он даже не использует delete. Он просто устанавливает эти значения в null.

1 голос
/ 08 марта 2010

Есть delete. Однако реальная потребность в этом будет редкой. Это не похоже на C ++ delete.

delete в JavaScript удалит свойство из объекта. Последующие обращения к этому свойству вернут неопределенное. Я предполагаю, что он сможет освободить любую связанную память при последующих сборках мусора.

0 голосов
/ 17 октября 2015

Ключевое слово "new" не имеет ничего общего с памятью. Он предназначен только для настройки цепочки прототипов.

// C++
Foo* foo = new Foo();                      // allocate and construct

// JS "sugar" using the new keyword
var foo = new Foo();                       // allocate and construct
assert(foo instanceof Foo);

// JS constructing objects without "new"
var foo = Object.create(Foo.prototype);    // allocate with prototype
Foo.call(foo);                             // construct
assert(foo instanceof Foo);

// construct Foo with missing prototype
var foo = {};                              // allocate without prototype
Foo.call(foo);                             // construct without prototype
assert(!(foo instanceof Foo));

// so the corollary operations in JS are
foo = {};
foo = null;

// where-as this is an error (or most certainly not what you want)
delete foo;

// and this is how delete is used
foo = {bar: 42};
assert(foo.bar === 42);
delete foo.bar;
assert(foo.bar === undefined);

// but by deleting a property, you remove the reference to the object
foo = {bar: {baz: 31}};
delete foo.bar;            // remove only reference to "bar" object
// JS GC will now take over

Так что нет, вы не можете удалять объекты. Но вы можете удалить ссылки на объекты, которые могут вызвать удаление объектов с помощью GC. Но, конечно, локальные переменные (и глобальные) не могут быть удалены. Они просто выходят из области видимости, отменяя ссылки на любые связанные объекты и потенциально освобождая память, но только если объект не был возвращен или на него все еще ссылаются в другом месте.

Важно понимать, что, поскольку JS не поддерживает указатели, GC может быть идеальным. В любой момент GC может просто пройти весь набор «видимых» объектов из любой встроенной функции и гарантировать, что он не пропустит ничего вроде циклов и т. Д.

Пока вы используете JS в функциональном стиле и не пытаетесь создавать глобальные объекты бога, которые связывают все воедино, управление памятью не должно быть проблемой.

...