节点js原型对象'self'var不存储正确的callback上下文

我是经验丰富的开发人员,但新的Java脚本和nodejs,我很抱歉,如果这个问题已被回答“原样”,但即使我已经去了多个例子和stackoverflow的答案,我没有find一个简单的完整例子的原型类用正确的“自我”var范围和绑定(这)。 我试了两个,都出错了,我会感谢您的帮助。 我尝试把var self = this; 在我的函数声明的开始,但是运行时,它实际上并没有通过函数代码,当它被设置为原型,所以,'这'设置不正确。

/** * Module Dependencies */ var cheerio = require('cheerio'); var http = require('http'); /** * Export */ module.exports = SimplePageGetter; function SimplePageGetter(pageLink) { this._pageLink = pageLink; } SimplePageGetter.prototype.getPage = function () { var self = this; http.request(self._pageLink, self._resultsPageHttpGetCallback).end(); }; SimplePageGetter.prototype._resultsPageHttpGetCallback = function (response) { var pageBody = ''; var self = this; //another chunk of data has been recieved, so append it to `str` response.on('data', function (chunk) { pageBody += chunk; }); //the whole response has been recieved, so we just print it out here response.on('end', function () { self._parsePage(pageBody); }); }; SimplePageGetter.prototype._parsePage = function (body) { console.log('page parsed'); } 

出于某种原因,调用getPage时,“self”是正确的,但将是http模块ClientRequest而不是_resultsPageHttpGetCallBack上的对象。 我该怎么做错了?

谢谢 ,

詹姆士

调用函数中设置self并不会做任何事情来改变被调用函数的内容。 所以看这个:

 SimplePageGetter.prototype.getPage = function () { var self = this; http.request(self._pageLink, self._resultsPageHttpGetCallback).end(); }; 

这仍然只是传递给http.requestself._resultsPageHttpGetCallback函数的http.requesthttp.request仍然将它作为一个普通的函数而不是一个方法来调用,所以this_resultsPageHttpGetCallback中将是undefined(严格模式)或全局对象(松散模式)。

self模式对于在相同范围(或嵌套范围)中创build的函数有用,例如:

 function someMethod() { var self = this; http.request(self._pageLink, function(err, data) { // Use `self` here to access object info }).end(); } 

这是有效的,因为我传递给http.request的匿名函数closures了 (有一个引用)创build它的上下文,并且该上下文具有selfvariables,所以函数可以访问selfvariables。

对于你在做什么, Function#bind会更合适:

 SimplePageGetter.prototype.getPage = function () { http.request(this._pageLink, this._resultsPageHttpGetCallback.bind(this)).end(); }; 

Function#bind创build一个新的函数,被调用时,将调用原来的function, this设置为一个特定的值。

更多关于this

  • 这里关于堆栈溢出: this关键字是如何工作的?
  • 在我贫血的小博客上: 神话的方法 | 你必须记住this

仅供参考,以下是应用于完整代码示例的Function#bind模式:

 /** * Module Dependencies */ var cheerio = require('cheerio'); var http = require('http'); /** * Export */ module.exports = SimplePageGetter; function SimplePageGetter(pageLink) { this._pageLink = pageLink; } SimplePageGetter.prototype.getPage = function () { http.request(this._pageLink, this._resultsPageHttpGetCallback.bind(this)).end(); }; SimplePageGetter.prototype._resultsPageHttpGetCallback = function (response) { var pageBody = ''; response.on('data', function (chunk) { pageBody += chunk; }); //the whole response has been recieved, so we just print it out here response.on('end', function () { this._parsePage(pageBody); }.bind(this)); }; SimplePageGetter.prototype._parsePage = function (body) { console.log('page parsed'); }; 

您可能会考虑ES2015(又名ES6)的新function,因为底层V8引擎支持它们(或者,您可以使用转换器从ES6input生成ES5代码),您现在可以在NodeJS中使用其中的许多function

以上是使用ES2015的:

  • …箭头函数,它从它们被定义的上下文inheritance,使self不必要的。

  • class关键字,它提供了一个更简洁的方式来编写构造函数和原型。

  • let关键字,只是因为,你知道,这是ES2015的代码。 🙂

应用这些:

 /** * Module Dependencies */ let cheerio = require('cheerio'); let http = require('http'); class SimplePageGetter { constructor(pageLink) { this._pageLink = pageLink; } getPage() { http.request(this._pageLink, response => { this._resultsPageHttpGetCallback(response); }).end(); } _resultsPageHttpGetCallback(response) { let pageBody = ''; response.on('data', chunk => { pageBody += chunk; }); //the whole response has been recieved, so we just print it out here response.on('end', () => { this.parsePage(pageBody); }); } _parsePage(body) { console.log('page parsed'); } } /** * Export */ module.exports = SimplePageGetter; 

请注意, class不像函数声明那样被提升,所以导出的标准位置通常在模块的底部。 如果你只有一个出口(就像你在这种情况下那样),但你可以这样做

 module.exports = class SimplePageGetter { //... }; 

最后但并非最不重要的:除非你真的需要_resultsPageHttpGetCallback_parsePage作为对象的属性(这是公共的),否则我可能会使它们成为私有函数,而不是接受SimplePageGetter实例作为标准参数,或者期望被调用即使它们不是方法,也是指它。

在这里,他们有一个论点:

 /** * Module Dependencies */ let cheerio = require('cheerio'); let http = require('http'); class SimplePageGetter { constructor(pageLink) { this._pageLink = pageLink; } getPage() { http.request(this._pageLink, response => { resultsPageHttpGetCallback(this, response); }).end(); } } function resultsPageHttpGetCallback(getter, response) { let pageBody = ''; response.on('data', chunk => { pageBody += chunk; }); //the whole response has been recieved, so we just print it out here response.on('end', () => { parsePage(getter, pageBody); }); } function parsePage(getter, body) { console.log('page parsed'); } /** * Export */ module.exports = SimplePageGetter; 

在这里,他们期望this被设置,所以我们通过Function#call他们:

 /** * Module Dependencies */ let cheerio = require('cheerio'); let http = require('http'); class SimplePageGetter { constructor(pageLink) { this._pageLink = pageLink; } getPage() { http.request(this._pageLink, response => { resultsPageHttpGetCallback.call(this, response); }).end(); } } function resultsPageHttpGetCallback(response) { let pageBody = ''; response.on('data', chunk => { pageBody += chunk; }); //the whole response has been recieved, so we just print it out here response.on('end', () => { parsePage.call(this, pageBody); }); } function parsePage(body) { console.log('page parsed'); } /** * Export */ module.exports = SimplePageGetter;