Скажем, у нас есть этот код (забудьте о прототипах на мгновение):
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 Specifically и node.js.
Кроме того, любые общие рекомендации на том, когда использовать, какая техника приветствуется. В моем определенном примере это действительно подходит мне для использования первого примера, но я знаю thath, внешняя функция будут много раз инстанцировать.
Насколько я понимаю, дело не столько в "компиляции" функции, сколько в том, что при каждом выполнении она имеет другую "область видимости".
Второй метод, который вы использовали, всегда будет иметь method
из той же области видимости.
Первый метод помещает method
внутрь области видимости вызова функции A()
. Поэтому любая информация, находящаяся внутри этой области видимости (var foo
, параметры функции и т.д.), хранится в этом экземпляре области видимости функции. Таким образом, каждый раз будет ссылаться один и тот же код функции, но он будет находиться в другой области видимости (и, следовательно, в другом "объекте").
Да, вы создаете новый Функциональный объект при каждой реализации объекта 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: из http://code.google.com/apis/v8/design.html , я бы подумал, что V8 компилирует закрытие один раз, когда создает скрытый класс, содержащий свойство метода
.
Я бы предположил, что она компилируется только один раз... потому что ключевое слово "this" относится к контексту выполнения... поэтому компилятору не нужно много знать о функции, чтобы интерпретировать ее.
Более того, когда вы объявляете переменную в нижней части функции, она все еще доступна в верхней части:
function test()
{
alert(hello);
// ...
var hello = 2;
}
То же самое с функциями. Я полагаю, что с учетом этих двух вещей, она не перекомпилируется каждый раз, когда вызывается A.
Mike
Представьте себе функцию как еще один объект, а затем, когда вы создаете новый, это просто копия старого, с измененной переменной данных. Вам не нужно повторно анализировать источник объекта, чтобы это произошло. Хорошая аналогия - это функциональные элементы в C ++, функциональные объекты в Lua, и я действительно не знаю многих других языков.
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 может зайти довольно далеко, если использовать его в расширенном режиме.
Метод не перекомпилирован.
Интерпретатор Javascript создаст новый закрывающий объект, содержащий внутренние методы и локальные переменные каждый раз, когда вы вызываете внешние методы.
Точная реализация зависит от механизма Javascript.