避免需要为javascript原型函数声明'var me = this'

时间:2011-03-15 20:16:57

标签: javascript oop closures javascript-objects

目前,我通过声明构造(常规函数)在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();
});

此代码输出预期的,但实际上它看起来效率低(每次调用createTest()时都会重新声明Test对象)?

Anyhoo,这看起来有点像hacky ......有没有一种完全不同的方式做到这一点更好?

编辑:我想这样做的真正原因是,像test2中那样的回调将引用正确的this

3 个答案:

答案 0 :(得分:2)

您可以做的是将当前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();

答案 1 :(得分:2)

我意识到你的问题没有用jQuery标记,但你在你的例子中使用它,所以我的解决方案也使用了jQuery。

我有时使用$.proxy函数来避免回调上下文。 Look at this simple jsfiddle example。来源如下。

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 :(得分:0)

大多数时候,我只是声明一个引用它的局部变量,无论我在回调中需要对它的引用:

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()等的回调函数。