that и this сидели на трубе…
Как известно, this
внутри вложенных функций (inner functions) равен глобальному объекту (global object). Из-за этого приходится писать нелепую конструкцию var that = this;
(господи, сколько же раз я написал эту строчку!)
Пример:
var test = {
init: function () {
this.txt = 'Test!';
var that = this;
window.setTimeout(function() {
alert(that.txt);
}, 1000);
}
};
Как же избавиться от ненавистного that
?
Для этого попробуем воспользоваться методом apply
, который позволяет задать контекст (чему будет равен this
) у функции. Однако, применить apply
к callback-функции передаваемой в setTimeout
нельзя, поскольку apply
сразу выполняет функцию к которой он применен. Поэтому напишем вспомогательный метод scope
.
Function.prototype.scope = function (o) {
var fn = this;
return function () {
return fn.apply(o, arguments);
};
};
Теперь перепишем наш пример, используя метод scope
.
var test = {
init: function () {
this.txt = 'Test!';
window.setTimeout(function () {
alert(this.txt);
}.scope(this), 1000);
}
};
Ура, мы избавились от that
!
Плюсы:
- Выкинули
var that = this;
- В inner function используем «родную» переменную
this
вместо трижды злоебучейthat
- Мне кажется, код стал выглядеть элегантнее
Спорные моменты:
- Экономии объема кода нет, может быть даже небольшое увеличение
- Возможно, ухудшилась читаемость кода, поскольку, не дочитав до конца определения функции, непонятно, на что же ссылается
this
Изначально хотел опубликовать эту заметку в Техногрете, но передумал — не могу с высокой трибуны рекомендовать решение, которым, возможно, сам не буду пользоваться :)
3 комментария:
ну вот и зря. надо было публиковать. умный поймёт и решит, как ЕМУ надо, а глупый и так ни черта не поймет :)
Есть такая библиотка Prototype JavaScript framework, и в ней функция bind(), делает то же самое, плюс позволяет задать часть аргументов (от 0 до всех).
Ух ты, мегареспект. Будем пробовать. Я как раз отказался от злоебучего $.each, подменяющего контекст, на dean’овский forEach.
Отправить комментарий