Search code examples
javascriptnode.jsecmascript-6ecmascript-5multiple-instances

instances of module functions/classes in nodejs


I have a project that was started as ES5.1, later I changed it to support ES6 so I was using async-await, let...

now I need to have module/object that is instance-like.

I found this post explaining the process, but...

when I do:

'use strict';

let _ = require('lodash');
var mappings;

function SafeRequestHandler(reqMappings) {

    if (!(this instanceof SafeRequestHandler)) {
        return new SafeRequestHandler((reqMappings));
    }

    mappings = reqMappings;
}

function safeHandleReq(req, res) {
    try {
        let pair = _.find(mappings, {'url': req.url});
        return pair.handler(req, res);
    } catch (err) {
        console.log(err);
    }
}

SafeRequestHandler.prototype.safe = safeHandleReq;

module.exports = SafeRequestHandler;

but now, each time I do:

var handler = require('../util/safeRequestHandler');

let handlerMappings = [
    {
        url: def.party_create,
        handler: partyCreate
    },
    {
        url: def.party_modify,
        handler: partyModify
    },
    {
        url: def.party_get,
        handler: partyGet
    }
];

var handle = new handler(handlerMappings).safe;

I get this.mappings REPLACED in SafeRequestHandler eg. it's NOT an instance.

so I tried ES6 approach defining the handler:

'use strict';

let _ = require('lodash');

class SafeRequestHandler {

    constructor(reqMappings) {
        this.mappings = reqMappings;
    }

    safeHandleReq(req, res) {
        try {
            let pair = _.find(this.mappings, {'url': req.url});
            return pair.handler(req, res);
        } catch (err) {
            console.log(err);
        }
    }

}

and instantiate it like:

let handlerMappings = [
    {
        url: def.party_create,
        handler: partyCreate
    },
    {
        url: def.party_modify,
        handler: partyModify
    },
    {
        url: def.party_get,
        handler: partyGet
    }
];

let handle = new SafeRequestHandler(handlerMappings).safeHandleReq;

..but this way I can't even reach out mappings in safeHandleReq(...). this is undefined, mappings is undefined

I think I just don't fully understand basic principles, so can you please correct&explain what is wrong with this two approaches?

Thanks!


Solution

  • You will lose the context if you store a method of a specific class instance into a variable.

    // handle doesn't have a pointer to its context (aka, this)
    let handle = new SafeRequestHandler(handlerMappings).safeHandleReq;
    // so handle() will output cannot read property mappings of undefined
    

    Change it to:

    const instance = new SafeRequestHandler(handlerMappings);
    
    const handle = (...args) => instance.safeHandleReq(...args);
    

    Further info here: Losing "this" context in JavaScript when passing around members