2015-05-10 106 views
-1

我想分配一个对象到一个原型,但我不断收到一个对象未​​定义的错误。我试图做到这一点指定对象到原型

//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); 
     }); 
    }); 
    } 
}; 
+1

我不能”重现问题。请显示实际的代码。 – thefourtheye

+1

什么是变量'x'? – jfriend00

+0

也许x不是函数,或者您将assignData作为回调/事件处理函数传递。如何使用原型和这个的价值在这里解释:http://stackoverflow.com/a/16063711/1641941你可以尝试一些控制台日志看到更多的输出(如console.log(this)) – HMR

回答

3

(见下更新,现在你已经发布的代码。)

这是最有可能的你调用方法的结果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); 
} 

在这两种情况下,问题是, thisassignData的调用中没有引用对象,而是全局对象。当通过属性引用调用函数而不是时,将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#bindArray#everythisArg说法:

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支持他们,和节点更新使用该版本的V8(包括那些将是太快了),你就可以做到这一点(注意两个=>以下):

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); 
    }); 
    // ... 
}); 
+0

谢谢。还有其他方法可以传递正确的“this”吗?使用http.get.bind(this)会更有效率吗? –

+0

@MikeF:无论你使用'self''或'Function#bind'和'thisArg'参数到'Array#every'(我已经添加了一个例子,如果你想这样做),该代码的效率将由HTTP操作驱动,而不是JavaScript。我的直觉是,如果你想微观优化(我不推荐),最有效的方法是在'http.get'调用之前调用'var paths = this.neighborhoodPaths',然后'paths [ element.name.toLowerCase()]。path = element.path;'在'every'回调中。但我非常怀疑这在现实世界中会起作用。 –