Это не ошибка jQuery, это неотъемлемая часть способа, которым JavaScript обрабатывает объекты.
В отличие от большинства других объектно-ориентированных языков, «this» является , а не ограниченным уровнем для метода в JavaScript; вместо этого он определяется исключительно тем, как вызывается функция:
Bob= {
toString: function() { return 'Bob!'; },
foo: function() { alert(this); }
};
Brian= {
toString: function() { return 'Brian!'; },
};
Bob.foo(); // Bob!
Bob['foo'](); // Bob!
Brian.foo= Bob.foo;
Brian.foo(); // Brian! NOT Bob
var fn= Bob.foo;
fn(); // window NOT Bob
Что вы делаете в случае:
$j('#MyButton').click( Bob.doSomething );
аналогичен последнему примеру с fn
: вы извлекаете функцию doSomething
из Боба и передаете ее в установщик обработчика событий jQuery как чистую функцию: она больше не имеет никакого отношения к Бобу или любому другому объекту, поэтому Вместо этого JavaScript передает глобальный объект window
. (Это одна из худших конструктивных особенностей JavaScript, поскольку вы, возможно, не сразу заметите, что window
не Bob
, и начнете обращаться к его свойствам, вызывая странные и запутанные взаимодействия и ошибки.)
Чтобы вспомнить Боба, вы обычно делаете функцию, как в ответе Никита, чтобы сохранить копию «Боба» в закрытии, чтобы ее можно было запомнить во время обратного вызова и использовать для вызова реального метода. Однако теперь есть стандартизированный способ сделать это в ECMAScript Fifth Edition:
$j('#MyButton').click( Bob.doSomething.bind(Bob) );
(Вы можете также добавить дополнительные аргументы в вызове bind
для вызова doSomething
обратно с ними, что удобно.)
Для браузеров, которые еще не поддерживают метод bind () пятого издания (который на данный момент является большинством из них), вы можете взломать собственную реализацию bind
(библиотека Prototype также делает это) что-то вроде:
if (!Object.bind) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}