Давайте разберемся с этим
$('#element').animate(
{'marginLeft': '50px'},
'slow',
function() {
myObject.methodTwo();
}
);
В этом примере вы передаете объект функции в качестве обратного вызова. Этот функциональный объект вызывается, когда анимация завершена. У него есть объект myObject
, общий доступ к которому осуществляется через замыкание, поэтому он может легко найти его и вызвать метод для него. Awesome!
$('#element').animate(
{'marginLeft': '50px'},
'slow',
myObject.methodTwo() // No more anonymous function
);
Здесь происходит нечто иное. В качестве обратного вызова здесь вы фактически передаете возвращаемое значение myObject.methodTwo()
, а не фактический функциональный объект. Таким образом, поскольку methodTwo()
ничего не возвращает, тогда undefined
фактически передается как обратный вызов. Это означает, что функция animate()
считает, что обратного вызова нет.
Так что, возможно, вы хотели попробовать это!
$('#element').animate(
{'marginLeft': '50px'},
'slow',
myObject.methodTwo // No more anonymous function or invocation
);
Ну, это все равно не сработает. Теперь вы передаете объект функции для обратного вызова, да, но он потеряет контекст (this
). Оказывается, что когда вы вызываете объект функции самостоятельно, то this
является глобальным объектом. Проверьте это:
var obj = {
foo: function() { console.log(this) }
};
obj.foo() // logs obj
var func = obj.foo;
func() // logs window (the global object in a browser)
Таким образом, вы не можете передать объект функции напрямую для обратного вызова, который должен вызываться как метод с объектом в качестве получателя. Внутри метода animate()
он выполняет для вас callback()
, то есть вызов, который не сохраняет для вас значения this
.
Так почему же это не сработало?
$('#element').animate(
{'marginLeft': '50px'},
'slow',
function() {
this.methodTwo(); // assuming 'this' refers to 'myObject'
}
);
Когда анонимная функция вызывается в качестве обратного вызова, как при разрыве метода, this
по умолчанию используется для оконного объекта. Так что этот код на самом деле вызывает window.methodTwo()
, который не существует, и он взрывается.
Итак, принятый стандартный JS способ сделать это вашим первым способом.
someFunc(arg1, arg2, function() {
someObj.someMethod()
});
Это всегда должно работать, даже если это кажется бесполезным, потому что вы вызываете функцию 2, чтобы сделать что-то одно. Но, как вы обнаруживаете, это наименее подвержен ошибкам.
Изучение того, как this
работает в JS, является болезненным опытом, но когда вы его получите, вы обнаружите, что правила довольно просты и просты в обращении.
Если вам все еще не нравится это, вы можете сделать некоторую хитрую магию js. Как и underscore.js метод bind () .
someFunc(arg1, arg2, _.bind(someObj.someMethod, someObj));
Возвращает функцию, которая всегда будет работать с someObj
как this
, которую можно безопасно использовать в качестве обратного вызова.
Или, если вы хотите попробовать CoffeeScript, у него есть жирная стрелка для сохранения контекста, которая компилируется в JS аналогично тому, что делает метод underscore.js bind()
.
someObj =
foo: ->
someFunc arg1, arg2, =>
this.bar()
bar: ->
alert 'got the callback!'
someObj.foo()
В этом случае объявление функции в стиле =>
сохраняет контекст области, в которой оно появляется, поэтому его можно безопасно использовать.