avoid hacks to properly bind to class in ES6?

271 views Asked by At

I find this rather cumbersome. I probably am doing it wrong or there is some easier way I'm unaware of (did not find much w/o knowing what to search for).

I want to avoid doing the following two workarounds to ensure this is correctly pointing to the DB class inside my methods:

this.connect = this.connect.bind(this);
db.connect.bind(db)

DB class:

'use strict';

const http = require('http');
const MongoClient = require('mongodb').MongoClient;

class DB {
  constructor(opts){
    this.opts = opts;
    this.dbUrl = process.env.MONGODB_URL;

    // anyway to avoid this hacK?
    this.connect = this.connect.bind(this);
    this.close = this.close.bind(this)
  }

  async connect(ctx, next){
    try {
      ctx.db = await MongoClient.connect(this.dbUrl); // fixes `this` being incorrect here
    } catch(err) {
      ctx.status = 500;
      ctx.body = err.message || http.STATUS_CODES[ctx.status];
    }

    await next();
  }

  async close(ctx, next){
    const result = await ctx.db.close();
    await next();
  }
}

module.exports = DB;

Calling the DB class method db.connect():

'use strict';

const Koa = require('koa');
const DB = require('./db');
const db = new DB();
const bodyParser = require('koa-bodyparser');
const router = require('koa-router');

const api = router();
const app = new Koa();
const cors = require('kcors');

app
  .use(bodyParser())
  .use(cors())
  .use(db.connect); // the above constructor copying fixes having to do `db.connect.bind(db)` here

  // without the constructor fix in class DB:

  .use(db.connect.bind(db)) // this gets annoying having to do this everywhere

Which is more "correct" or if there is a 3rd way which avoids both of these workarounds? Also what are the pros and cons of each if these are the only two ways to bind class methods to their class.

1

There are 1 answers

0
cwingrav On

There is a series of helpful auto binding functions. I wrote one just today to improve on them. Take a look: https://www.npmjs.com/package/auto-bind-inheritance

npm install --save auto-bind-inheritance

const autoBind = require('auto-bind-inheritance');

Just put autoBind(this); in the child class constructor and all methods and method pointers will be bound to the object, just like you would expect in C++/Java. This basically calls bind for you.

So, if you have trouble using methods as callbacks that get bound to another 'this', this package will fix it.