节点 js 原型对象 'self' var 没有为回调存储正确的上下文
node js prototype object 'self' var does not store correct context for callback
我是经验丰富的开发人员,但是 java 脚本和 nodejs 的新手,如果这个问题已经得到回答,我深表歉意 'as-is' 但是即使我已经看过多个示例和 Whosebug 的答案,我还是做到了找不到具有正确 'self' var 作用域和 bind(this) 的原型 class 的简单完整示例。
我都试过了,但都出错了……非常感谢你的帮助。
我试着把
变种自我=这个;
在我的函数声明的开头,但是当 运行 时,当它被设置为原型时它实际上并没有通过函数代码,因此,'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');
}
出于某种原因,'self' 在调用 getPage 时是正确的,但将是 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
仍会将其作为普通函数而不是方法来调用,因此 _resultsPageHttpGetCallback
中的 this
将是未定义的(严格模式)或全局对象(松散模式)。
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
创建一个 new 函数,调用时将调用原始函数,并将 this
设置为特定值。
关于this
的更多信息:
- 在 Stack Overflow 上: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)的新特性,其中许多特性现在可以在 NodeJS 中使用,因为底层 V8 引擎支持它们(或者,您可以使用 transpiler 从 ES6 输入生成 ES5 代码)。
以上是使用 ES2015 的:
...箭头函数,它从定义它们的上下文中继承 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
作为对象的属性(public),否则我可能会将它们设为私有函数,它要么接受 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;
我是经验丰富的开发人员,但是 java 脚本和 nodejs 的新手,如果这个问题已经得到回答,我深表歉意 'as-is' 但是即使我已经看过多个示例和 Whosebug 的答案,我还是做到了找不到具有正确 'self' var 作用域和 bind(this) 的原型 class 的简单完整示例。 我都试过了,但都出错了……非常感谢你的帮助。 我试着把 变种自我=这个; 在我的函数声明的开头,但是当 运行 时,当它被设置为原型时它实际上并没有通过函数代码,因此,'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');
}
出于某种原因,'self' 在调用 getPage 时是正确的,但将是 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
仍会将其作为普通函数而不是方法来调用,因此 _resultsPageHttpGetCallback
中的 this
将是未定义的(严格模式)或全局对象(松散模式)。
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
创建一个 new 函数,调用时将调用原始函数,并将 this
设置为特定值。
关于this
的更多信息:
- 在 Stack Overflow 上: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)的新特性,其中许多特性现在可以在 NodeJS 中使用,因为底层 V8 引擎支持它们(或者,您可以使用 transpiler 从 ES6 输入生成 ES5 代码)。
以上是使用 ES2015 的:
...箭头函数,它从定义它们的上下文中继承
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
作为对象的属性(public),否则我可能会将它们设为私有函数,它要么接受 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;