Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 methods get a null "this" and class variables are inaccessible [duplicate]

I'm using an ES6 class to bundle some functionality together in Node. Here's (basically) what it looks like:

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;

I thought that with ES6 classes, the way to assign public variables was to simply reference this and the way to initialize those variables via a constructor is exactly how it shows up in my class definition.

Here's how I'm calling the class (in a separate file):

var Processor = require('./processDocs');

var pr = new Processor(id);
var docs;
pr.process();

Here's the issue, when I console.log out this from the constructor, I get my { id: id } value as predicted; however, whenever I log out this in getDocs when process is running, it's null. BUT, when I log out this in process() right before the waterfall, I get my original object.

Is there any reason for this?

Btw, I'm using node: v0.10.33 and babel-node 4.6.6 and I run babel-node with the --harmony flag. Before anyone asks, I can't update to a newer Node version due to a major dependency which is stuck at v0.10.x.

EDIT I was able to create a workaround but it's not very es6-like. The issue seems to be with async.waterfall. I had to use a .bind to fix it:

    async.waterfall([
      this.getDocs.bind(this),
      this.alterDocs.bind(this),
      this.reindexSearch.bind(this)
    ]);
like image 800
antjanus Avatar asked Mar 31 '15 00:03

antjanus


1 Answers

You can use arrow functions inside your class as they auto bind this. You can write your class methods as:

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

see this MDN article: "Arrow functions capture the this value of the enclosing context"

like image 142
ziv Avatar answered Oct 05 '22 22:10

ziv