OO JavaScript - Избегание self = this
Кто-нибудь знает, как обойти объявление var self = this при использовании JavaScript в стиле OO? Я вижу это довольно часто, и мне было любопытно, если это что-то, что вам нужно сделать, или если есть действительно способ (возможно, библиотека классов?), Который позволяет вам обойти это? Я понимаю, почему это необходимо (у этого есть функция). Но вы никогда не знаете, какие умные способы могут быть там.
Например, я обычно кодирую свои "классы", подобные этому в JS:
function MyClass() {
}
MyClass.prototype = {
firstFunction: function() {
var self = this;
$.ajax({
...
success: function() {
self.someFunctionCall();
}
});
},
secondFunction: function() {
var self = this;
window.setTimeout(function() {
self.someOtherFunction();
}, 1000);
}
};
Ответы
Ответ 1
В вашей первой функции вы можете сделать это...
$.ajax({
context: this,
success: function() {
this.someFunctionCall();
}
});
Во втором случае вы можете сделать это, хотя вам нужно будет пропустить .bind()
в старых браузерах...
window.setTimeout(function() {
this.someOtherFunction();
}.bind(this), 1000);
С помощью jQuery вы также можете сделать это...
window.setTimeout($.proxy(function() {
this.someOtherFunction();
}, this), 1000);
Ответ 2
Нет, вам нужно сделать это, если хотите обратиться к this
в другом контексте (например, обратном вызове), поскольку в противном случае он будет переназначен другому объекту, например window
.
Кстати, self
- это соглашение на пионе - в JavaScript люди обычно используют соглашение that = this
. Но это всего лишь вопрос личного вкуса.
Ответ 3
ES5 добавил стандартный метод под названием bind
, который позволяет вам привязать this
к функции, а также к первому n числу параметров. В приведенном выше примере вы можете избежать использования self
, вызвав bind
.
$.ajax({
...
success: function() {
this.someFunctionCall();
}.bind(this);
});
Для браузеров, не относящихся к ES5, вы можете использовать для него такую прокладку, как найденную здесь: https://github.com/kriskowal/es5-shim
Как утверждают, я бы избегал использовать self
в вашем шаблоне кодирования, потому что self
определяется как глобальная переменная, которая равна window
, которая является глобальной областью. Другими словами, если вы случайно забыли определить self
, вы без проблем получите глобальную область действия как значение, а не исключение. Если вместо этого вы используете that
, вы получите исключение (если только кто-то из вас не определил его).
Ответ 4
Некоторые фреймворки javascript имеют свои собственные механизмы обработки событий, которые позволяют устанавливать контекст для функции обработчика. Таким образом, вместо использования self = this
вы можете просто указать this
в качестве контекста.
Другая возможность, которая приходит мне на ум, - передать контекст где-нибудь в глобальной области. Как
function MyClass() {
MyClass.instances.push(this);
}
MyClass.instances = new Array();
MyClass.getInstanceBySomeRelevantParameter = function(param) {
for (var i = 0; i < MyClass.instances.length; i++)
if (condition(param))
return MyClass.instances[i];
}
...
success: function(event) {
MyClass.getInstanceBySomeRelevantParameter(event).someFunctionCall();
}
Ответ 5
Вы всегда можете привязать свои методы к this
, а затем использовать его следующим образом:
function MyClass() {
}
MyClass.prototype = {
firstFunction: function() {
var funct = someFunctionCall.bind(this);
$.ajax({
...
success: function() {
funct();
}
});
},
secondFunction: function() {
var funct = someOtherFunction.bind(this);
window.setTimeout(function() {
funct();
}, 1000);
}
};
Для свойств просто назначьте их другой переменной.
Ответ 6
Я обманул JSFiddle и придумал ниже. Предполагается, что вы используете пространство имен верхнего уровня. Это делает так, что вам нужно только объявить себя один раз (внизу). Я завернул класс в анонимную функцию, поэтому у меня не было бы глобального масштаба. Сценарий: http://jsfiddle.net/bdicasa/yu4vs/
var App = {};
(function() {
App.MyClass = function() { }
App.MyClass.prototype = {
firstFunction: function() {
console.log('in first function');
console.log(self === this); // true
},
secondFunction: function() {
window.setTimeout(function() {
self.firstFunction();
console.log(self === this); // false
}, 100);
}
};
var self = App.MyClass.prototype;
})();
var myClass = new App.MyClass();
myClass.secondFunction();