我是一位经验丰富的开发人员,但是对Java脚本和Node.js还是陌生的,如果这个问题已按原样回答,我深表歉意,但是即使我遍历了多个示例和stackoverflow答案,也没有找到原型类的简单完整示例正确的'self'变量作用域和绑定(this)。
我都尝试过,但都出错了...感谢您的帮助。
我试过
var self = this;
在我的函数声明的开头,但是在运行时,将其设置为原型时,它实际上并没有经过函数代码,因此,“ 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
并不会改变被调用函数中this
的内容。所以看这个:
SimplePageGetter.prototype.getPage = function () {
var self = this;
http.request(self._pageLink, self._resultsPageHttpGetCallback).end();
};
那仍然只是将对
self._resultsPageHttpGetCallback
函数的引用传递给http.request
。 http.request
仍将其仅作为普通函数而不是方法来调用,因此this
中的_resultsPageHttpGetCallback
将为未定义(严格模式)或全局对象(宽松模式)。self
模式对于在同一作用域(或嵌套作用域)中创建的函数很有用,例如:function someMethod() {
var self = this;
http.request(self._pageLink, function(err, data) {
// Use `self` here to access object info
}).end();
}
之所以可行,是因为我要传递给
http.request
的匿名函数在创建它的上下文中关闭(具有引用),并且该上下文具有self
变量,因此该函数可以访问self
变量。对于您正在做的事情,
Function#bind
会更合适:SimplePageGetter.prototype.getPage = function () {
http.request(this._pageLink, this._resultsPageHttpGetCallback.bind(this)).end();
};
Function#bind
创建一个新函数,该函数在被调用时将在this
设置为特定值的情况下调用原始函数。关于
this
的更多信息:在堆栈溢出中:How does the
this
keyword work?在我贫乏的小博客上:Mythical Methods | You Must Remember
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)的新功能,因为底层V8引擎支持它们,所以您现在可以从v4开始在NodeJS中使用其中的许多功能(或者,您可以使用编译器从ES6输入生成ES5代码)。
以下是使用ES2015的内容:
... arrow函数,它们从定义它们的上下文继承
this
,从而使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
实例作为标准参数,或期望使用this
引用它,即使它们不是方法。在这里,他们有一个论点:
/**
* 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;