-2

I am trying to understand JavaScript inheritance and I hit a road block. I am not familiar with JavaScript's prototype based inheritance. I am still using old NodeJS version so I can't use classes.

Could you tell me why following code prints the same values for different workers and how can I prevent it?

var Manager = require('./manager');

var worker1 =  new Manager.getWorker('foo');
var worker2 =  new Manager.getWorker('bar');

console.log(worker1.config);
console.log(worker2.config);

//Implementation Details

//Manager
(function() {
    'use strict';

    function Manager() {

    }

    Manager.getWorker = function(slug) {
        var Worker = null;
        try {
            Worker = require('./workers/' + slug);
            Worker = new Worker();
        } catch (e) {
            console.log('Worker error: cannot initiate worker');
        }
        return Worker;
    };
    module.exports = Manager;
})();

//foo.js
(function () {
    var _abstract = require('../abstract_worker');
    var _util = require('util');


    var config = {
        "slug": "foo",
        "name": "Foo Worker"
    };

    function Foo() {
        this.config = config;
        Foo.super_.apply(this,arguments);
    }
    _util.inherits(Foo, _abstract);
    module.exports = Foo;
})();

//bar.js
'use strict';

(function () {
    var _abstract = require('../abstract_worker');
    var _util = require('util');


    var config = {
        "slug": "bar",
        "name": "Bar Worker"
    };

    function Bar() {
        this.config = config;
        Bar.super_.apply(this,arguments);
    }
    _util.inherits(Bar, _abstract);
    module.exports = Bar;
})();

(function() {
    'use strict';
    //config
    var _ = require('lodash');

    var default_config = {
        number_of_job: 1
    };

    function AbstractWorker() {
        if (!this.config) {
            this.config = {};
        }

        if (!_.isString(this.config.slug)) {
            throw new Error('config.slug is undefined.');
        }

        if (!_.isString(this.config.name)) {
            throw new Error('config.name is undefined.');
        }
        this.config = _.merge(default_config, this.config);
    }
    module.exports = AbstractWorker;

})();

EDIT: Thanks to @Bergi I found out the source of the error. It seems Lodash's merge recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. In my code it seems I also made a typo and wrote in wrong order. I just leave it as it is maybe it can help others in the long run.

Meanteacher
  • 2,031
  • 3
  • 17
  • 48
  • JS classes still use prototypal inheritance, by the way. They just hide it. – mhodges Jan 09 '18 at 20:48
  • 1
    Is this really the smallest and simplest demonstration you could come up with? – melpomene Jan 09 '18 at 20:51
  • 1
    I would recommend Kyle Simpson's [`YDKJS`](https://github.com/getify/You-Dont-Know-JS/), specifically [this chapter](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch5.md) – mhodges Jan 09 '18 at 20:53
  • @melpomene I am sorry. I tried to make it as small as possible. I am sorry again for the trouble. – Meanteacher Jan 09 '18 at 20:53
  • Well, your example immediately fails in the first line for me: `var Manager = require('./manager');` – melpomene Jan 09 '18 at 20:55
  • @melpomene You have to put them into separate files.. hence the comments like `//foo.js` and `//bar.js` – mhodges Jan 09 '18 at 20:56
  • 1
    `manager.js` must be in the same folder which I gave in my code. There also must be folders named `workers` which has `foo.js` and `bar.js` – Meanteacher Jan 09 '18 at 20:57
  • 1
    No, that's too complicated. A [mcve] should be pasteable into a simple file. – melpomene Jan 09 '18 at 20:57
  • @melpomene I am sorry for the trouble. I am not competent in JS as you are sir. – Meanteacher Jan 09 '18 at 20:59
  • @melpomene Keep in mind, the OP's issue may be a result of misunderstanding how module loading works, in which case, the require statements are very relevant to the code – mhodges Jan 09 '18 at 20:59
  • @mhodges In that case an attempt at reducing the example may point out the issue and lead to a better/different question. – melpomene Jan 09 '18 at 21:00
  • @melpomene It's possible - just something to keep in mind, that's all. – mhodges Jan 09 '18 at 21:01
  • A bit clumsy but it can help : https://stackoverflow.com/a/44733777/1636522. –  Jan 09 '18 at 21:19

1 Answers1

0
this.config = _.merge(default_config, this.config);

is your problem. It assigns the same default_config object to all workers.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I really appreciate your help sir. I use `config` in the code. How can I set a config per worker which won't affect others? – Meanteacher Jan 09 '18 at 21:01
  • I found out the error. It seems loadash `merge` recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Thanks for the help. – Meanteacher Jan 09 '18 at 21:17