【问题标题】:avoid needing to declare 'var me = this' for javascript prototype functions避免需要为 javascript 原型函数声明 'var me = this'
【发布时间】:2011-07-16 02:35:39
【问题描述】:

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

【问题讨论】:

标签: javascript oop closures javascript-objects


【解决方案1】:

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

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

【讨论】:

    【解决方案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();
    });
    

    【讨论】:

    • 非常酷!好点,我应该用 jQuery 标记...我想我会玩这个,看看这在实践中能满足我的需求。
    【解决方案3】:

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

    【讨论】:

    • 是的,但是如果您在任何原型中都有回调,this 将不会引用该对象。抱歉不够清楚。请查看编辑。
    • 嗯,这是否意味着对于 Test 对象中的每个函数,我必须在构造函数中添加this.func = (function(){...}).bind(this)?如果是这种情况,我认为在每个 Test.prototype 函数的顶部声明 var me = this 会更干净......
    • @Hersheezy - 您不一定需要这样做。如果由我决定,我会将 this 引用保留在需要它的函数的本地。这样您就可以避免创建工厂样式的对象。
    • 我想我开始明白你在说什么了。我可以看到避免在原型函数内部执行回调是一种有用的模式。至于您提到的“避免工厂样式对象创建”,我将不得不多考虑一下...不是特别熟悉这种模式...
    猜你喜欢
    • 2016-09-21
    • 2011-04-23
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 2012-07-15
    • 2021-03-17
    • 2013-05-23
    • 2012-04-29
    相关资源
    最近更新 更多