избежать необходимости объявлять 'var me = this' для функций прототипа javascript - PullRequest
4 голосов
/ 15 марта 2011

В настоящее время я создаю объекты в javascript, объявляя конструкцию (обычную функцию), затем добавляю методы к прототипу, например так:

function Test(){
}
Test.prototype.test1 = function(){
    var me = this;
}

Однако я бы хотел избежать объявления var me = this ввершина каждой функции.Кажется, что работает следующее, но кажется, что это будет очень неэффективно:

$(document).ready(function(){
var n = 0;
(function(){

     function createTest(){
        var me;
        function Test(){
            this.n = n;
            this.testArr = [1, 2, 3, 4];
            n++;
        }

        Test.prototype.test1 = function(){
            me.test2();
        };
        Test.prototype.test2 = function(){
            alert(me.n);
            $.getJSON('test.php', {}, function(reply)
                //want to be able to use 'me' here
                me.newField = reply;
            });
        };

        var t = new Test();
        me = t;
        return t;
    }
    window['createTest'] = createTest;
})();

var t = createTest();
t.test1();
var t2 = createTest();
t2.test1();
t.test1();
});

Этот код выводит ожидаемый результат, но действительно ли он так же неэффективен, как выглядит (объект Test повторно объявляется каждый раз, когда выcall createTest ())?

В любом случае, это может показаться немного странным ... Есть ли совершенно другой способ сделать это лучше?

РЕДАКТИРОВАТЬ: реальная причина, по которой я хотел бысделать это так, чтобы обратные вызовы, такие как в test2, имели ссылки на правильный this.

Ответы [ 3 ]

2 голосов
/ 16 марта 2011

Я понимаю, что ваш вопрос не был помечен jQuery, но вы используете его в своем примере, поэтому мое решение также использует jQuery.

Иногда я использую функцию $.proxy дляизбегать контекста обратного вызова. Посмотрите на этот простой пример jsfiddle .Источник ниже.

function Test(){
    this.bind();
}

Test.prototype.bind = function(){
    $('input').bind('change', $.proxy(this.change, this)); 
    // you could use $.proxy on anonymous functions also (as in your $.getJSON example)
}
Test.prototype.change = function(event){ 
    // currentField must be set from e.target
    // because this is `Test` instance
    console.log(this instanceof Test);          // true
    console.log(event.target == $('input')[0]); // true
    this.currentField = event.target;           // set new field
};

function createTest(){
    return new Test();
}

$(function(){ // ready callback calls test factory
    var t1 = createTest();
});
2 голосов
/ 15 марта 2011

Что вы можете сделать, это связать текущее значение this с function и сохранить копию где-нибудь. (Ради эффективности.)

if (!Function.prototype.bind) {
    // Most modern browsers will have this built-in but just in case.
    Function.prototype.bind = function (obj) {
        var slice = [].slice,
            args = slice.call(arguments, 1),
            self = this,
            nop = function () { },
            bound = function () {
                return self.apply(this instanceof nop ? this : (obj || {}),
                                    args.concat(slice.call(arguments)));
            };
        nop.prototype = self.prototype;
        bound.prototype = new nop();
        return bound;
    };
}

function Test(n) {
    this.n = n;
    this.callback = (function () {
        alert(this.n);
    }).bind(this)
}

Test.prototype.test1 = function () {
    this.test2();
}

Test.prototype.test2 = function () {
    doSomething(this.callback);
}

function doSomething(callback) {
    callback();
}

var t = new Test(2);
t.test1();
0 голосов
/ 16 марта 2011

В большинстве случаев я просто объявляю локальную переменную, которая ссылается на это, где бы мне ни понадобилась ссылка на это в обратном вызове:

function Foo() {
}

Foo.prototype.bar = function() {
  var that=this;
  setTimeout(function() {
     that.something="This goes to the right object";
  }, 5000);
}

В качестве альтернативы, вы можете использовать bind () следующим образом:

Function Foo() {
   this.bar = this.bar.bind(this);
   // ... repeated for each function ...
}

Foo.prototype.bar = function() {
}

Это дает вам то, что каждый раз, когда вы создаете новый экземпляр Foo, методы привязываются к текущему экземпляру, поэтому вы можете использовать их в качестве функций обратного вызова для setTimeout () и др.

...