ES6方法获得null“this”,类变量不可访问

时间:2015-03-31 00:13:13

标签: node.js ecmascript-6 babeljs

我正在使用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()时,我会得到原始对象。

这有什么理由吗?

顺便说一句,我正在使用节点:v0.10.33和babel-node 4.6.6,我使用--harmony标志运行babel-node。在有人要求之前,我无法更新到更新的Node版本,因为主要的依赖关系停留在v0.10.x

编辑我能够创建一个变通方法,但它不像es6那样。问题似乎与async.waterfall有关。我不得不使用.bind来修复它:

    async.waterfall([
      this.getDocs.bind(this),
      this.alterDocs.bind(this),
      this.reindexSearch.bind(this)
    ]);

4 个答案:

答案 0 :(得分:3)

ES6没有改变“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(){});

输出

processDocs {id: 10}
processDocs {id: 10}
processDocs {id: 10}
undefined

正如你所看到的,最后一个是undefines,它调用了“docsAsFunction”,因为你没有直接从它的类调用该函数,因此上下文是不同的。

您可以阅读它,例如here

答案 1 :(得分:0)

我自己创造了以下功能。

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)

或者这个命令

fixThisPointer2(this, ['foo', 'foo2', 'foo3'])

答案 2 :(得分:0)

您可以在类中使用箭头函数,因为它们会自动绑定它。您可以将类方法编写为:

 getDocs = (cb) => {
    // console.log(this) will not returns null
    docs
      .query(qb => {
         qb.where('id', this.id);
      })
      .fetch()
      .then(function(documents) {
        cb(null, documents);
      })
    ;
 }

请参阅this MDN article:"箭头函数捕获封闭上下文的此值"

答案 3 :(得分:0)

考虑将process()的正文更新为:

process() {
  // console.log(this) returns { id: id }
  async.waterfall([
    (cb)=>{this.getDocs(cb);},
    (documents,cb)=>{this.alterDocs(documents,cb);},
    (cb)=>{this.reindexSearch(cb);}
  ]);
}

使用箭头函数可确保使用正确的上下文调用类的成员函数。