суббота, 18 февраля 2012 г.

Примеры, когда замыкания вредят

1. Допустим, мы на определенные ссылки хотим добавлять аргумент, который будет предаваться на сервер, и который непостоянный и вычисляется определенным образом на странице (в нашем примере он будет статическим;)):
var quantaty = 5;

function addGlobalQueryOnClick(linkRef){    
    if(linkRef){        
        linkRef.onclick = function(){            
            this.href += ('?quantaty='+escape(quantaty));
            return true;
        };
    }
} 
Не достаток такого подхода вот в чем. Каждый раз когда мы вызываем эту функцию, то внутри создается НОВАЯ анонимная, которая подхватывает для себя еще и замыкание. Если функция addGlobalQueryOnClick будет достаточно много раз вызвана на странице, то будет задействовано кучу лишних ресурсов - созданных анонимных обработчиков и их замыканий со ссылками на свою линку. Фцнкция же обрабочик события ни чем не отличается для каждой из ссылки, поэтому будет хорошо, если все они будут использовать ее одну, да еще и без существования ненужного замыкания.


Вот оптимальный вариант:
var quantaty = 5;

function addGlobalQueryOnClick(linkRef){    
    if(linkRef){        
        linkRef.onclick = forAddQueryOnClick;
    }
}

function forAddQueryOnClick(){
    this.href += ('?quantaty='+escape(quantaty));
    return true;
}

2. Почему все-таки сейчас преобладает создание имитации классов с определением методов не в обьекте(определение в конструкторе в момент его выполнения), а в его прототипе? Ответ станет очевиден если посмотреть на первый пример, помня о предыдущем примере:
function ExampleClass(param){    
    this.method1 = function(){
        ... // method body.
    };
    this.method2 = function(){
        ... // method body.
    };
    this.method3 = function(){
        ... // method body.
    };
    this.publicProp = param;
}
Как мы видим созданется каждый раз при создании обьекта еще и новые обьекты-функций для него, а это вообщето расточительство, и кроме того контекст выполнения конструктора каждый раз сохраняется в замыканиях созданных для каждого метода. Вот же обьекты-функции(методы) создаются только один раз и размещаются в свойстве контуктора prototype, а все созданные им инстанции получают ссылки на эти обьекты-методы, и их замыкания просто хранят ссылки на глобальный контекст иполнения:
function ExampleConst(param){
    this.publicProp = param;
}

ExampleConst.prototype.method1 = function(){
    ... // method body.
};
ExampleConst.prototype.method2 = function(){
    ... // method body.
};
ExampleConst.prototype.method3 = function(){
    ... // method body.
};
3. Циклическая ссылка приводит к утечкам памяти: Ой!:
function foo(element, a, b) {
  element.onclick = function() { /* uses a and b */ };
}
Наша аннонимная функция в своем замыкании хранит ссылки на element( при этом эта переменная даже может и не использоваться в теле функции), на a и на b Другое дело!:
function foo(element, a, b) {
  element.onclick = bar(a, b);
}

function bar(a, b) {
  return function() { /* uses a and b */ }
}

Комментариев нет:

Отправить комментарий