Перекомпилированы ли замыкания в javascript? - PullRequest
16 голосов
/ 11 мая 2010

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

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 достаточно умны, чтобы не каждый раз создавать новую функцию 'method'? В частности, Google v8 и node.js.

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

Ответы [ 6 ]

7 голосов
/ 11 мая 2010

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

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

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

3 голосов
/ 11 мая 2010

Да, вы создаете новый объект 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's the same Function object

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

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


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

2 голосов
/ 11 мая 2010

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

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

Точная реализация зависит от движка Javascript.

0 голосов
/ 11 мая 2010
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» и функции «method», тогда как во втором примере она доступна всем, у кого есть доступ к экземпляру «A».

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

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

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

0 голосов
/ 11 мая 2010

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

0 голосов
/ 11 мая 2010

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

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

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

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

Mike

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...