【问题标题】:assigning object to prototype将对象分配给原型
【发布时间】:2015-05-10 07:22:39
【问题描述】:

我正在尝试将对象分配给原型,但我不断收到对象未定义的错误。我正在尝试这样做

//x.prototype.y = {};
StreetEasy.prototype.neighborhoodPaths = {};

稍后在代码中,我尝试在另一个原型函数中访问该对象并使用

//x.prototype.assignData = function(z, a){
  // this.y[z] = a;
//}
StreetEasy.prototype.findNeighborhoodPath = function(areaQuery, callback){
  var data = {q: areaQuery, key: this.apiKey, format: this.format};
  var query = qs.stringify(data);
  var url = AreaSearchUrl + '?' + query;

  var areaQ = areaQuery.toLowerCase();
  if (this.neighborhoodPaths[areaQ]) {
      callback(this.neighborhoodPaths[areaQ].path);
   } else {
      http.get(url, function(response){
        response.setEncoding('utf8');
        response.on('data', function (rData){
          rData = JSON.parse(rData);
          callback(rData);
          rData.areas.every(function(element){
    -----------error is here-> this.neighborhoodPaths[element.name.toLowerCase()].path = element.path;
          });

        }).on('error', function(e){
               console.error('ERROR: ' + e.message + ' | ' + e.statusCode );
      });
    });
  }
};

节点不断返回

TypeError:无法读取未定义的属性 z。我做错了什么?

编辑更多代码:

StreetEasy.prototype.neighborhoodPaths = {}; 
StreetEasy.prototype.findNeighborhoodPath = function(areaQuery, callback){
  var data = {q: areaQuery, key: this.apiKey, format: this.format};
  var query = qs.stringify(data);
  var url = AreaSearchUrl + '?' + query;

  var areaQ = areaQuery.toLowerCase();
  if (this.neighborhoodPaths[areaQ]) {
      callback(this.neighborhoodPaths[areaQ].path);
   } else {
      http.get(url, function(response){
        response.setEncoding('utf8');
        response.on('data', function (rData){
          rData = JSON.parse(rData);
          callback(rData);
          rData.areas.every(function(element){
    -----------error is here-> this.neighborhoodPaths[element.name.toLowerCase()].path = element.path;
          });

        }).on('error', function(e){
               console.error('ERROR: ' + e.message + ' | ' + e.statusCode );
      });
    });
  }
};

【问题讨论】:

  • 我无法重现该问题。请出示实际代码。
  • 变量x是什么?
  • 也许 x 不是函数,或者您将 assignData 作为回调/事件处理程序传递。这里解释了如何使用原型和 this 的值:stackoverflow.com/a/16063711/1641941 你可以尝试一些控制台日志以查看更多输出(如 console.log(this))

标签: javascript node.js prototype


【解决方案1】:

(既然您已经发布了代码,请参阅下面的更新。)

这很可能是由于您调用assignData 的方式造成的。例如,这将起作用:

var obj = new x();
obj.assignData("foo", "bar");

这不会:

var obj = new x();
f = obj.assignData;
f("foo", "bar");

出于同样的原因,这不会:

callMeBack(obj.assignData, "foo", "bar");
function callMeBack(method, z, a) {
    method(z, a);
}

在这两种情况下,问题在于对assignData 的调用中的this 没有引用对象,而是全局对象。当您通过属性引用调用函数not 时,this 被设置为全局对象(在松散模式下;在严格模式下它将是undefined)。 通过属性引用调用它的动作将this设置为属性来自的对象。

更多(在我的博客上):


更新,现在您已经发布了代码。我将假设 findNeighborhoodPath 是您在原始问题中称为 assignData 的函数。

问题确实是你失去了this,但不是完全按照上面的方式。

您传递的回调http.get 将被调用,this 指的是全局对象,而不是调用findNeighborhoodPath 的实例;同样,您传递给 Array#every 的回调将有 this 引用全局对象,因为您没有告诉它做其他事情。

如果你想使用那个实例,最简单的方法是声明一个引用它的变量,然后使用这个变量:

var self = this; // <== Variable to remember `this`
http.get(url, function(response) {
    response.setEncoding('utf8');
    response.on('data', function(rData) {
        rData = JSON.parse(rData);
        callback(rData);
        rData.areas.every(function(element) {
            self.neighborhoodPaths[element.name.toLowerCase()].path = element.path;
        //  ^^^^ --- using it
        });

    }).on('error', function(e) {
        console.error('ERROR: ' + e.message + ' | ' + e.statusCode);
    });
    // ...
});

或者,您可以使用Function#bind 和Array#every 的thisArg 参数:

http.get(url, function(response) {
    response.setEncoding('utf8');
    response.on('data', function(rData) {
        rData = JSON.parse(rData);
        callback(rData);
        rData.areas.every(function(element) {
            this.neighborhoodPaths[element.name.toLowerCase()].path = element.path;
        }, this); // <=== Note passing `this` as the second arg to `every`

    }).on('error', function(e) {
        console.error('ERROR: ' + e.message + ' | ' + e.statusCode);
    });
    // ...
}.bind(this)); // <=== Note the .bind(this)

在 JavaScript 的下一个版本 ECMAScript6 中,我们将拥有“胖箭头”函数,它具有“词法 this 绑定”,这是一个花哨的术语,意味着函数中的 this 将与 this 相同是在创建函数的上下文中。因此,一旦 V8 支持它们,并且 Node 更新为使用该版本的 V8(这两者都将很快推出),您将能够做到这一点(注意下面的两个 =&gt;):

http.get(url, (response) => {
    response.setEncoding('utf8');
    response.on('data', function(rData) {
        rData = JSON.parse(rData);
        callback(rData);
        rData.areas.every((element) => {
            this.neighborhoodPaths[element.name.toLowerCase()].path = element.path;
        });

    }).on('error', function(e) {
        console.error('ERROR: ' + e.message + ' | ' + e.statusCode);
    });
    // ...
});

【讨论】:

  • 谢谢。还有其他方法可以传递正确的“this”吗?使用 http.get.bind(this) 会不会更高效?
  • @MikeF:无论你使用self 还是Function#bind 和thisArg 参数到Array#every 都不太重要(如果你想这样做,我已经添加了一个示例),该代码的效率将由 HTTP 操作而不是 JavaScript 驱动。我的直觉是,如果您想进行微优化(我不推荐),最有效的方法是在 http.get 调用之前使用 var paths = this.neighborhoodPaths;,然后在 every 回调中使用 paths[element.name.toLowerCase()].path = element.path;。但我非常怀疑这在现实世界中是否重要。
猜你喜欢
  • 2015-09-22
  • 1970-01-01
  • 2020-06-12
  • 2020-05-22
  • 2018-12-20
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 2016-06-16
相关资源
最近更新 更多