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();