Javascript:从对象方法内部调用回调函数,产生意想不到的结果

Javascript: Callback function called from inside object method producing unexpected results

本文关键字:意想不到 结果 函数 回调 对象 方法 调用 内部 Javascript      更新时间:2023-09-26

我有一个名为RouteLeg的简单对象,它包含一组Lat/Lng值,并且能够使用google maps api渲染两个Lat/Lng点之间的行驶路线。

在renderRoad方法中我调用了google maps api DirectionsService。route方法,在回调函数上使用闭包,这样它就可以访问RouteLeg对象(self是定义为self = this的对象成员):

  
directionsService.route(request, (function(obj) {
    return function(result, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            obj.getDisplay().setDirections(result);
        }
    };
})(self));

只有当RouteLeg(一个DirectionsRenderer对象)的display成员变量被声明为private (var display)而不是public (this.display)时,代码才有效。当display被声明为public时,它在回调函数中的值总是为null。

我对JS比较陌生,不理解这种行为。我错过了什么?

(注:

当我改变display变量的作用域时,我也改变了this。getDisplay函数匹配。directionsService和map是全局变量)。

function RouteLeg(aStart, aEnd) {
  var start = aStart; //an object that contains lat/lng values
  var end = aEnd; //lat/lng object
  this.display = null;  //does not work, only works as when declared as a var 
  var self = this;
  this.getDisplay = function() {
    return this.display;
  }
  this.render = function() {
    renderRoad();
  }
  var renderRoad = function() {
    if (this.display == null) {
      this.display = new google.maps.DirectionsRenderer({
        suppressMarkers: true
      });
    }
    this.display.setMap(map);
    var request = {
      origin: new google.maps.LatLng(start.getLat(), start.getLng()),
      destination: new google.maps.LatLng(end.getLat(), end.getLng()),
      travelMode: google.maps.TravelMode.DRIVING
    };
    //directionsService is a global variable for now
    directionsService.route(request, (function(obj) {
      return function(result, status) {
        if (status == google.maps.DirectionsStatus.OK) {
          obj.getDisplay().setDirections(result);
        }
      };
    })(self));
  }
}

这是因为renderRoad没有RouteLeg的执行上下文。这意味着当你执行renderRoad时,this指的是全局对象,而不是routeg的一个实例。

为了使它工作,要么在RouteLeg实例上定义renderRoad:

this.render = function() {
  this.renderRoad();
}
this.renderRoad = function() {

或者使用call/bind/apply将renderRoad的执行上下文设置为RouteLeg实例

this.render = function() {
  renderRoad.call(this);
}
var renderRoad = function() {

在没有上下文的情况下调用renderRoad函数,因此设置它的代码。Display将它设置在另一个对象上然后是self传递的对象。

renderRoad.apply(this)