【问题标题】:Avoid losing this reference and why it's happening避免丢失此参考及其发生原因
【发布时间】:2011-11-16 16:01:49
【问题描述】:

我有这个有错误的小提琴 --> http://jsfiddle.net/Osoascam/AkZZr/6/ (这是没有错误的版本)--> http://jsfiddle.net/Osoascam/AkZZr/7/

其中有一个模块(如主应用程序)、一个处理 Ajax 调用的Module.AjaxInterface、一个处理与电子邮件收件箱相关的任务的Module.Modules.Inbox 和一个处理多个显示页面的模块。所有这些都是使用模块模式完成的。

现在,您可以看到有很多回调。我想知道this 在这些电话中会发生什么...

我不知道this 参考发生了什么以及如何保存它:

getMessages: function(params) {
                var parameters = params || {};
                params = {
                    // Please note I'm using this, which equals the module
                    successCallback: this.pretendRender,
                    successCallbackParameters: parameters,
                    json: params.json
                };
                var test = new Module.AjaxInterface(params);
                test.ajaxCall();
            },

因此,对模块本身内部函数的调用是有效的……然后,它调用test.ajaxCalls,而后者又调用pretendRender()。现在,在pretendRender 我有这个:

 pretendRender: function(data, parameters) {
                // LINE 106 that is causing the ERROR
                // It says "this.addColor() is not defined and THIS = window now
                data.color = this.addColor();
                parameters.successCallback(data);
            },

            addColor: function() {
              return "#AD9";
           }

我的问题是...this 引用发生了什么?为什么改成window?我该如何解决?我知道我可以使用callapply,但是函数pretendRender 正在AjaxInterface 上被调用,并且对Modules.Inbox 的引用已经丢失(除非我使用caller,我不能在"strict") 下。我知道我可以将this 传递给AjaxInterface 来保留它,但我真正想要的是真正了解正在发生的事情并创建一个优雅的解决方案。

【问题讨论】:

    标签: javascript callback this module-pattern


    【解决方案1】:

    this.pretendRender 只是一个函数的引用/指针,函数调用时this 的上下文取决于很多东西:

    a.b.c = this.pretendRender;
    a.b.c(); 
    

    this 将在 c 内成为 b,因为 c 引用的函数被作为 b 的属性调用


    window.a = this.pretendRender;
    a(); 
    

    this 将设置为global object,因为a 引用的函数被作为global object 的属性调用


    a.b.c = this.pretendRender.bind( this );
    a.b.c();
    

    this 将是 c 内的原始 this 无论如何,因为 c 引用的函数是一个绑定函数,它调用原始函数并将上下文设置为原始 this.bind 存在于现代浏览器中,但 must be included to be sure 可用。


    a.b.c = this.pretendRender;
    a.b.c.call( someObject );
    

    this 将在 c 内为 someObject,因为它是明确给出的。


    由于您使用的是 jQuery,因此您可以使用 successCallback: $.proxy( this.pretendRender, this ) 而不是 this.pretendRender.bind( this );

    jsfiddle

    【讨论】:

    • 嗯...我明白了...这不是我希望“this”在回调中...我只需要一种方法来调用 addColor()... 它说如果我保持原样,它是未定义的
    • 你调用this.addColor(),当this设置正确时它会起作用。所以:successCallback: $.proxy( this.pretendRender, this ) 如果您使用的是 jQuery,那么您唯一需要更改的就是它应该可以工作。请参阅此处jsfiddle.net/AkZZr/8。我这样做只是改变了它并开始工作。
    • 太完美了!非常感谢!
    【解决方案2】:

    this 始终是调用函数的对象。它改变。 this.pretendRender 不是在那个时间点附加到 this 对象的方法。它只是一个正在传递的函数。如果您想保证 this 在该上下文中与该方法一起传播,您需要将this 绑定 到该函数。像这样的东西(使用闭包):

    var me = this;
    params = {
        successCallback: function() { return me.pretendRender.apply(me, arguments); },
        ...
    }
    

    underscore.js 框架使用_.bind() 提供了更好的方法。

    【讨论】:

    • 谢谢你的解释......但我正在做successCallback:this.pretendRender,(即传递对该函数的引用而不是调用函数本身)。如果我这样做me.pretendRender.apply(me, arguments);,我不会调用该函数吗?此外,该函数的参数应用于Module.AjaxInterface,并且该函数在那里执行,在callback(data, parameters); 中调用它的引用这就是为什么我不知道如何使用apply,因为函数引用被传递然后在另一个模块。
    • 如果不是 function() {...} 包装调用,它会被调用。这将创建一个匿名函数,稍后将调用该函数将 this 引用保存在 me 变量中。
    • 好的,我试过successCallback: function(data) { return me.pretendRender.call(me, data);,它返回了addColor is not defined。 (在这个 js 小提琴上 --> jsfiddle.net/Osoascam/AkZZr/9
    猜你喜欢
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 2015-06-06
    • 2014-05-04
    • 2016-09-05
    • 2016-11-19
    • 2011-05-04
    • 2013-02-17
    相关资源
    最近更新 更多