Подтвердить что ты не робот

Являются ли замыкания в javascript перекомпилированы

Скажем, у нас есть этот код (забудьте о прототипах на мгновение):

function A(){
  var foo = 1;
  this.method = function(){
    return foo;
  }
}
var a = new A();

- внутренняя функция, перекомпилированная каждый раз, когда выполняется функция A? Или лучше (и почему) сделать это вот так:

function method = function(){ return this.foo; }
function A(){
  this.foo = 1;
  this.method = method;
}
var a = new A();

Или javascript-механизмы достаточно умны, чтобы не создавать новую функцию "метод" каждый раз? В частности, Google v8 и node.js.

Кроме того, любые общие рекомендации о том, когда использовать эту технику, приветствуются. В моем конкретном примере мне действительно нравится использовать первый пример, но я знаю, что внешняя функция будет создаваться многократно.

4b9b3361

Ответ 1

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

Второй метод, который вы использовали, всегда будет иметь method из той же области.

Первый метод помещает method в область вызова функции A(). Таким образом, любая информация, находящаяся внутри этой области (var foo, параметры функции и т.д.), Хранится в этом экземпляре области видимости функций. Таким образом, один и тот же функциональный код будет ссылаться каждый раз, но он будет в другой области (и, следовательно, другой "объект" ).

Ответ 2

Да, вы создаете новый объект Function при каждом экземпляре объекта A. Вы можете продемонстрировать это следующим образом:

function A(){
  var foo = 1;
  this.method = function(){
    return foo;
  }
}
var a = new A();
var b = new A();
alert(a.method == b.method); // Returns false; two different Function objects

Если вы хотите повторно использовать один и тот же объект Function, сделайте метод свойством прототипа, а не экземплярами.

function B() {
  this.foo = 1;
}

B.prototype.method = function() {
  return this.foo;
}

var a = new B();
var b = new B();
alert(a.method == b.method); // Returns true; it the same Function object

Изменить: насколько я знаю, нет причин делать что-то вроде первой версии, кроме создания частных переменных в объекте JavaScript. В исходном примере foo является закрытым. Ничто не может получить к нему доступ непосредственно извне объекта. К сожалению, когда вы создаете большое количество объектов, используя эту технику, это может повлиять на производительность и объем памяти.

В моем коде я использую соглашение об именах, чтобы различать свойства "public" и "private". Я называю частные свойства с подчеркиванием в качестве первого символа. Поэтому, если я вижу что-то вроде myObject._someMethod(), я знаю, что что-то не так.


Edit2: Из http://code.google.com/apis/v8/design.html я бы подумал, что V8 компилирует замыкание один раз, когда он создает скрытый класс, который содержит method.

Ответ 3

Метод не перекомпилирован.

Интерпретатор Javascript создаст новый объект замыкания, содержащий внутренние методы и локальные переменные, каждый раз, когда вы вызываете внешние методы.

Точная реализация зависит от механизма Javascript.

Ответ 4

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

Кроме того, когда вы объявляете переменную в нижней части функции, она все еще доступна вверху:

function test()
{
  alert(hello);
  // ...
  var hello = 2;
}

Это то же самое с функциями. Я бы поверил с этими двумя вещами в виду, что он не перекомпилируется каждый раз, когда вызывается A.

Mike

Ответ 5

Представьте себе функцию как еще один объект, а затем, когда вы создаете новую, это просто копия старой, с измененной переменной. Вам не нужно повторно анализировать источник объекта, чтобы это произошло. Хорошая аналогия - это функциональные функции в С++, объекты функций в Lua, и я действительно не знаю многих других языков.

Ответ 6

function A(){
  var foo = 1;
  this.method = function(){
    return foo;
  }
}

не может быть скомпилирован в

function method = function(){ return this.foo; }
function A(){
  this.foo = 1;
  this.method = method;
}

потому что функциональность изменится. Первый пример имеет переменную "foo", которая видна только конструктору "A" и функции "метод", тогда как во втором примере доступно все, имеющее доступ к экземпляру "A".

Его можно скомпилировать в

function method = function(){ return 1; }
function A(){ 
  this.method = method;
}

Но я не думаю, что какой-нибудь механизм javascript там зайдет так далеко, но если вы сможете предварительно обработать ваши файлы и готовы приложить дополнительные усилия, компилятор закрытия google может пойти довольно далеко, если он используется в расширенном режиме.