期待JavaScript对象中正确的调用上下文(this)

时间:2010-12-13 12:49:14

标签: javascript scope this

考虑一下:

window.onload = function () {
    myObj.init();
};

var myObj = {
    init: function () {
        console.log("init: Let's call the callMe method...");

        //callMe is not defined...
        callMe();

        //Works fine!
        this.callMe();
    },

    callMe: function () {
        console.log('callMe');
    }
};

由于init函数以这种方式调用(myObj.init),我希望this在init函数中是myObj。如果是这种情况,为什么callMe函数会失败?如何在不使用init主体中的this上下文的情况下调用callMe函数? (实际上,通过函数一遍又一遍地使用this来调用对象方法太烦人了。那么拥有单个对象有什么意义呢?)

我想知道如何解决这个问题,以便使用上面代码中的第一个调用来调用callMe方法?

2 个答案:

答案 0 :(得分:8)

this永远不会隐含在JavaScript中,因为它在其他一些语言中也是如此。虽然有办法,但使用with语句:

init: function () {
    console.log("init: Let's call the callMe method...");

    // Make `this` implicit (SEE BELOW, not recommended)
    with (this) {
        // Works
        callMe();
    }
},

......这通常是一个坏主意。 Douglas Crockford可能写了一个更好的描述为什么这是一个坏主意,你可以找到here。基本上,使用with几乎不可能告诉代码将要执行的操作(并且如果您在with语句中执行其他任何,则会减慢代码的速度来自this对象。)

这不是JavaScript的this与其他语言不同的唯一方式。在JavaScript中,this完全由如何调用函数定义,而不是函数定义的。当您执行this.callMe()(或等效this["callMe"](),或当然foo.callMe()等)时,会发生两个事件:从属性中检索函数引用,并以特殊方式调用函数,将this设置为属性来自的对象。如果您没有通过该属性调用函数,则调用不会设置任何特定的this值,并且您将获得默认值(这是全局对象;浏览器上为window)。这是进行调用以设置this是什么的行为。我在我的博客herehere上的几篇文章中深入探讨了这一点。

如果您查看所有函数对象上可用的JavaScript callapply函数,则可以使此(无双关语)更清晰。如果我这样做:

callMe.call({});

...它会将callMe函数调用空白对象({})作为this

基本上,只需习惯输入this即可。 :-)使用与对象关联的属性和方法仍然很有用,即使没有隐式this的语法方便(和混淆!)。

答案 1 :(得分:2)

您还可以使用模块模式,它捕获闭包内的所有私有变量,因此您可以在没有this的情况下自由使用它们,因为它们位于相同的范围。然后,您可以选择要公开的方法/变量:

var myObj = (function () {
   var init = function () {
      callMe(); // This now works
   };

   var callMe = function () {
      ...
   };

   // Now choose your public methods (they can even be renamed):
   return {
      init: init, // Same name
      callMyName: callMe // Different name
   };
}) ();

现在:

myObj.init(); // Works
myObj.callMyName(); // Works
myObj.callMe(); // Error