Вопрос заключается в том, что обработчики событий устанавливают свои собственные значения для this
при вызове функции обратного вызова. Это значение, как правило, связано с обработчиком события, а не с объектом, к которому привязан метод. Например, в вашем примере:
document.getElementById('foo').onClick(myObj.myFunc);
this
указатель в myFunc
будет установлен на элемент DOM, который имел обработчик события (в данном случае, foo
элемент). Но это не myObj
, поэтому myFunc
в этом случае не смог получить доступ к каким-либо своим собственным переменным экземпляра с помощью указателя this
(обычный способ доступа методов к данным экземпляра).
Итак, если у вас есть метод, который хочет получить доступ к собственным данным экземпляра, когда он вызывается непосредственно обработчиком событий, вам нужно сделать что-то другое, кроме как просто передать метод обработчику событий. Есть пара способов обойти эту проблему.
Один из способов сделать это так использовать .bind()
, который возвращает новую функцию заглушки кто есть функция, чтобы установить this
перед вызовом функции, как это:
document.getElementById('foo').addEventListener('click', myObj.myFunc.bind(myObj));
В этом случае .bind()
фактически возвращает новую функцию заглушки кто есть функция должна установить значение this
до myObj
до того, как оно называет myFunc
.
Вы также можете сделать это вручную, сами, как это:
document.getElementById('foo').addEventListener('click', function(e) {
myObj.myFunc();
});
Но, как вы можете видеть, .bind()
обеспечивает ярлык, который занимает меньше кода (именно поэтому он был изобретен).
Потенциальным недостатком использования .bind()
в некоторых случаях является то, что вы больше не имеют доступа к значению this
, что вызывающий обратного вызова бы установить себя, потому что .bind()
бросил это значение прочь и заменить его вместе с своя. В приведенном выше примере обработчика событий это не проблема, потому что исходный источник события может быть доступен через аргумент e
, который передается обработчику события, чтобы он не был потерян, если вам это нужно.
Я не знаю сколько-нибудь значимой разницы в потреблении памяти или сборке мусора между двумя описанными выше методами. Оба создают новую функцию, которая используется для вызова оригинала и для вызова функции this
при вызове исходной функции. Оба будут иметь тот же срок службы мусора.
Оказывается, что одна вещь, которая сбивает с толку вас в том, что объекты в JavaScript, назначаются или передаются по указателю (некоторые называют его по ссылке, но имеет некоторые коннотации, которые не применяются здесь, так что я буду использовать фраза по указателю).
var x = {};
x.myFunc = function() {console.log("hello");};
x.myFunc(); // generates "hello" in the console
var t = x.myFunc; // save reference to the function that x.myFunc currently points to
delete x.myFunc; // remove property myfunc from the x object
t(); // generates "hello" in the console
t()
все еще работает после того, как событие x.myFunc был удален, потому что оба т и x.myFunc имели ссылку (или указатель) к одной и той же функции. Выполнение delete x.myFunc
просто удалило свойство myFunc из объекта x
. Функция, которую указывают x.myFunc
, будет только «освобождена» GC, если нет других ссылок на нее. Но есть другая ссылка на эту функцию в t
, поэтому она не освобождена, и t()
может использовать ее до тех пор, пока существует t
.
Это должно объяснить это: [Как получить доступ к правильному 'this'/context внутри обратного вызова?] (Http://stackoverflow.com/a/20279485/218196) –
Но я не думаю, что это причина для идиомы в этом случае. Я знаю, что делает связка. Возможно, я должен был сформулировать вопрос, привязывает ли связанная копия функции к обратному вызову DOM какие-либо преимущества, помимо привязки к получателю? – Ben
Дополнительно к Felix: '.bind' - это дешевый способ создания частично прикладных функций в JS – zerkms