我正在使用 ES6 类将 Node 中的一些功能捆绑在一起。这是(基本上)它的样子:
class processDocs {
constructor(id) {
this.id = id;
// console.log(this) returns { id: id }
}
getDocs(cb) {
// console.log(this) returns null
docs
.query(qb => {
qb.where('id', this.id);
})
.fetch()
.then(function(documents) {
cb(null, documents);
})
;
}
alterDocs(documents, cb) {
//some logic
}
reindexSearch(cb) {
//some logic
}
process() {
// console.log(this) returns { id: id }
async.waterfall([
this.getDocs,
this.alterDocs,
this.reindexSearch
]);
}
}
export default processDocs;
我认为对于 ES6 类,分配公共变量的方法就是简单地引用
this
,而通过构造函数初始化这些变量的方法正是它在我的类定义中显示的方式。
这是我调用该类的方式(在单独的文件中):
var Processor = require('./processDocs');
var pr = new Processor(id);
var docs;
pr.process();
问题是,当我从构造函数中
console.log
输出 this
时,我得到了预测的 { id: id }
值;但是,每当我在 this
运行时注销 getDocs
时,它都是空的。但是,当我在瀑布前的 process
中注销 this
时,我得到了原来的对象。这有什么原因吗?
顺便说一句,我正在使用节点:
process()
和babel-node
v0.10.33
,并且我使用4.6.6
标志运行babel-node。在有人问之前,我无法更新到较新的 Node 版本,因为主要依赖项停留在 --harmony
。编辑
我能够创建一个解决方法,但它不太像 es6。问题似乎出在v0.10.x
。我不得不使用
async.waterfall
来修复它:.bind
考虑这个例子
async.waterfall([
this.getDocs.bind(this),
this.alterDocs.bind(this),
this.reindexSearch.bind(this)
]);
输出是
class processDocs {
constructor(id) {
this.id = id;
console.log(this)
}
getDocs(cb) {
console.log(this)
}
alterDocs(documents, cb) {
//some logic
}
reindexSearch(cb) {
//some logic
}
process() {
console.log(this)
}
}
var process = new processDocs(10);
var docs = process.getDocs(function(){});
var processInstance = process.process();
var docsAsFunction = process.getDocs;
docsAsFunction(function(){});
如您所见,最后一个是 undefines,它正在调用“docsAsFunction”,因为您没有直接从其类中调用该函数,因此上下文不同。
您可以阅读相关内容,例如
这里编辑 2024 年 - 因为它“仍然是一件事”,我正在扩展答案。有多种解决方案。
永远不要将函数“从其实例中取出”。如果您稍后需要调用该函数,只需保留整个实例,例如这样:
processDocs {id: 10}
processDocs {id: 10}
processDocs {id: 10}
undefined
class A {
constructor(id) {
this.id = id;
}
someFunction(){
console.log(this);
}
}
const a1 = new A(5);
const a2 = new A(20);
const arr = [a1, a2];
// some business logic
arr.forEach(a => a.someFunction());
和课程。当您需要存储库、控制器、服务等文件时,它默认会创建单例,这正是您想要的(它基本上类似于 Java 中的 @Autowired,但是是本机的)。
例如this
somethingService.js
用作 doSomething()
,或者您只需要函数本身并直接使用 somethingService.doSomething()
。
doSomething()
const someDefaultValue = 10;
export function doSomething() {
console.log(someDefaultValue);
}
。我认为这是一个有点hacky的解决方案,但考虑到JavaScript中
this
的奇怪行为,this
的工作方式更像其他语言中的self
,所以这是一种方法。
this
class Simple {
constructor(id) {
this.id = id;
self = this;
}
showThis(text) {
console.log(this, ` ** ${text} **`)
}
}
class SimpleWithSelf {
constructor(id) {
this.id = id;
const self = this;
}
showThis(text) {
console.log(self, ` ** ${text} **`)
}
}
const simple = new Simple(10);
simple.showThis("normal usage using instance of class");
const showThisFn = simple.showThis;
showThisFn("function using without instance");
const simpleWithSelf = new SimpleWithSelf(10);
simpleWithSelf.showThis("normal usage using instance of class with self");
const showThis = simpleWithSelf.showThis;
showThis("function using without instance with self");
参见这篇 MDN 文章
getDocs = (cb) => {
// console.log(this) will not returns null
docs
.query(qb => {
qb.where('id', this.id);
})
.fetch()
.then(function(documents) {
cb(null, documents);
})
;
}
的正文更新为:
process()
使用箭头函数可确保使用正确的上下文调用类的成员函数。
process() {
// console.log(this) returns { id: id }
async.waterfall([
(cb)=>{this.getDocs(cb);},
(documents,cb)=>{this.alterDocs(documents,cb);},
(cb)=>{this.reindexSearch(cb);}
]);
}
然后,当我需要它时,我在构造函数中使用这个命令
let bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; //from coffeescript's => operator
//use in a class's constructor to make the this pointer always refer to the object in which a function resides
function fixThisPointer(_this, func){
_this[func.name] = bind(_this[func.name], _this);
}
function fixThisPointer2(_this, funcNameArray){
for (name of funcNameArray){
_this[name] = bind(_this[name], _this);
}
}
或者这个命令
fixThisPointer(this, foo)