简体   繁体   English

在 JavaScript 中使用“this”的最终方法

[英]Definitive way to use "this" in JavaScript

I am beginning to define classes in JavaScript, and I have a lot of troubles with the keyword this .我是JavaScript开始定义类的,关键字this让我很头疼。

Here is an example of what I want to do:这是我想做的一个例子:

function MyMap() {

    this.map = new google.maps.Map(....);

    google.maps.event.addListener(this.map, 'idle', function() {
        this.mapIdle();    // PROBLEM: "this" undefined
    });

    this.mapIdle = function() {
        google.maps.event.addListener(marker, 'click', function() {
            $("button").click(function() {
                $.ajax({
                    success: function() {
                        this.map.clearInfoWindows(); // PROBLEM: "this" undefined
                    }
                });
            });
        });
    }
}

As you can see in the comments, this won't work here, because it is used inside a closure .正如您在评论中看到的, this在这里不起作用,因为它是在闭包中使用的。

I have started using workarounds like:我已经开始使用以下解决方法

var that = this;
google.maps.event.addListener(this.map, 'idle', function() {
    that.mapIdle();
});

Or even where you have to define a callback function around your callback function (seriously.!).或者甚至你必须在你的回调 function 周围定义一个回调function(真的。!)。

This is extremly ugly and doesn't work everywhere.这是非常丑陋的,并且在任何地方都不起作用。 When I get a lot of nested lambda functions (as in the example I gave), I have no idea how to use a class attribute.当我得到很多嵌套的 lambda 函数时(如我给出的示例),我不知道如何使用 class 属性。

What is the best and most correct way to do that?最好和最正确的方法是什么?

The easiest way is to define a self variable (or that , if you don't mind a non-semantic variable name) as you already mentioned:正如您已经提到的,最简单的方法是定义一个self变量(或者that您不介意非语义变量名的话):

function MyMap() {
   var self = this;

   // in nested functions use self for the current instance of MyMap
}

Noting that you have to do it again for methods you add to the prototype (if they use nested functions):请注意,对于添加到原型的方法(如果它们使用嵌套函数),您必须再次执行此操作:

MyMap.prototype.myMethod = function() {
   var self = this;
   // use self in nested functions
};

You should also read up on the .bind() method , noting that it doesn't work for IE <= 8.您还应该阅读.bind()方法,注意它不适用于 IE <= 8。

The question you linked to about defining a callback around your callback is to solve a different problem, ie, setting up an appropriate closure structure to allow functions that are nested inside a loop to have access to the appropriate loop counter value(s).您链接到的关于围绕回调定义回调的问题是为了解决不同的问题,即设置适当的闭包结构以允许嵌套在循环内的函数可以访问适当的循环计数器值。 That has nothing to do with the this issue.this题无关。 (And can easily be combined with the self technique when needed.) (并且可以在需要时轻松地与self技术相结合。)

If you're using jQuery, $.proxy is handy for this:如果您使用的是 jQuery, $.proxy对此很方便:

http://api.jquery.com/jQuery.proxy/ http://api.jquery.com/jQuery.proxy/

You can just assign the object and the function to local varibles, then they are included in the closures for the callback functions:您可以将 object 和 function 分配给局部变量,然后将它们包含在回调函数的闭包中:

function MyMap() {

  var map = new google.maps.Map(....);

  var mapIdle = function() {
    google.maps.event.addListener(marker, 'click', function() {
      $("button").click(function() {
        $.ajax({
          success: function() {
            map.clearInfoWindows();
          }
        });
      });
    });
  };

  this.map = map;
  this.mapIdle = mapIdle; // Is this needed?

  google.maps.event.addListener(this.map, 'idle', function() {
    mapIdle();
  });

}

In JavaScript, this is reassigned with every single function call.在 JavaScript 中,每次调用this都会重新分配它。

It's just something you have to be aware of in JavaScript. It can be confusing at first, but once you know a few simple rules, it's actually pretty straightforward.这只是您在 JavaScript 中必须注意的事情。起初可能会造成混淆,但是一旦您了解了一些简单的规则,实际上就非常简单了。

If it's a method call like myObj.doSomething() , then this will be automatically set to myObj inside of doSomething() .如果它是像myObj.doSomething()这样的方法调用,那么this将自动设置为doSomething()内的myObj

If you want to explicitly control the value of this when making a function call, you can use doSomething.apply() or doSomething.call() to control what this is set to inside the function. That's what event handler callbacks do.如果您想在调用 function 时显式控制this的值,您可以使用doSomething.apply()doSomething.call()来控制 function 中this的设置。这就是事件处理程序回调所做的。 They explicitly set this to point to the object that created the event (something which is very useful).他们明确地将this设置为指向创建事件的 object(这非常有用)。 You can read more about .apply() and .call() on MDN.您可以在 MDN 上阅读有关.apply().call() () 的更多信息。

If you just call a regular function, then this will be set to the global object which in a browser is the window object.如果你只是调用一个常规的 function,那么this将被设置为全局 object,在浏览器中是window object。

All callback functions will have their value of this messed with because every function call changes this .所有回调函数的this值都会被弄乱,因为每次 function 调用都会更改this Since your event handler is a callback and the success handler is a callback in the Ajax function, you should expect that the value of this will not be preserved from the surrounding code.由于您的事件处理程序是一个回调,而成功处理程序是 Ajax function 中的一个回调,因此您应该期望this的值不会从周围的代码中保留下来。 There are work-arounds using proxy or bind functions, but usually it's just as easy to capture the previous value of this in a closure and just access it from there with something like var self = this;有使用代理或绑定函数的变通方法,但通常在闭包中捕获this的先前值并从那里使用类似var self = this;的东西访问它同样容易。 . .

In your circumstance, when you want access to a this pointer from outside the event handler, the right thing is to just save it to a local variable that you will have access to in the event handler or even in the Ajax call that is in the event handler.在您的情况下,当您想要从事件处理程序外部访问this指针时,正确的做法是将它保存到您可以在事件处理程序中甚至在 Ajax 调用中访问的局部变量事件处理程序。 There is no cleaner way to do it.没有更清洁的方法来做到这一点。 This way you have access to both the this pointer from the event or the Ajax call and the this pointer from your calling object like this:这样您就可以访问事件或 Ajax 调用中的this指针以及调用 object 中的this指针,如下所示:

    var self = this;
    self.mapIdle = function() {
        google.maps.event.addListener(marker, 'click', function() {
            $("button").click(function() {
                $.ajax({
                    success: function() {
                        self.map.clearInfoWindows(); // PROBLEM: "this" undefined
                    }
                });
            });
        });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM