Home > Software design >  Share object between javascript modules
Share object between javascript modules

Time:07-12

Have searched for this, but looks like I'm using the wrong terms. Mostly find things about C , C#, node, PHP classes etc.


Say one have two modules A and B and a script main.

  • A exports farm
  • B exports print and uses A.farm
  • main imports A and B

But B depends on the same state of A.farm as main.


The way I have done this now is:

  1. main imports A
  2. main imports B
  3. B has a initialize function where it get a reference to A.farm from main.

Example:

  • A
let animal = 'donkey';
export const farm = {
    get_animal: () => animal,
    set_animal: a => animal = a
};
  • B
let farm, color;
export const initialize = env => {
    farm = env.farm;
    color = env.COLOR;
};

export const print = () => {
    console.log(
        'The', farm.get_animal(),
        'is going to be painted', color, '.'
    );
};
  • main
import {farm} from 'A';
import {print, initialize as initialize_b} from 'B';

const COLOR = 'red';
initialize_b({farm, COLOR});

farm.set_animal('cat');
print();

The cat is going to be painted red.


Is it the way to do it?

Question is if this is the way to do it? In the real project there is about 5 dependencies in B from main and 3 exports from B to main.

The code of B was initially part of main but as it can be categorized under one theme I found it better to have in a separate module it keeps main cleaner.

It feels a bit wonky.

Earlier, in no-module-code, I have typically had a PROJECT = {} object that I include first then attach shared functions and other things trough that.

I could have a import-export module, something like:

import_export

import {farm} from 'A';
import {print, initialize as initialize_b} from 'B';

const COLOR = 'red';

initialize_b({farm, COLOR});

export {farm, print, COLOR};

Then import the exports in main. But not sure if that would be any cleaner. The import_export could end up with a lot of exports and main lot of imports.

CodePudding user response:

Javascript supports OOP, classes etc., it seems your can use some of OOP methodologies. Instead of exporting ton of functions, you can instantiat a B object and use its methods.

Example:

A.js:

export class Farm {
    constructor(animal='donkey') {
        this.animal = animal;
    }
    get_animal: () => this.animal;
    set_animal: (a) => { this.animal = a }
};

B.js:

export class B {
    constructor(farm,  color) {
        this.farm = farm;
        this.color = color;
    }
    toString() {
        return 'The '   this.farm.get_animal()   ' is going to be painted '   this.color   '.'
    );
};

Main.js:

Import {Farm} from "./A.js"
Import {B} from "./B.js"

const someFarm = new Farm("cat")
const b = new B(someFarm, "red")
//invoke any B method like b.someUtil()
console.log(b) // The cat is going to be painted red.

CodePudding user response:

Is it the way to do it?

No. But not for the structure of your imports and exports, the number of dependencies, or your modularisation in general, but rather because your modules have global state. Avoid that, or where you cannot avoid it, keep it confined in main.js.

The usual solution here is to use OOP - see @Mercury's answer for a nice implementation. Instead of storing state in global (or module-level) variable, store in objects, and provide ways to create many objects of the same kind and set up its references to other objects.

The alternative, for smaller projects and where you know you're not gonna need it, is to simply have the modules import one another directly. In test most frameworks, you still can usually provide mocks for whole modules, otherwise this would be a real annoyance. Here's a small example:

// A.js
let animal = 'donkey';
export function getAnimal() { return animal; }
export function setAnimal(a) { animal = a; }
// B.js
import { getAnimal } from 'A';
import { color } from 'settings';

export function print() {
    console.log(`The ${getAnimal()} is going to be painted ${color}.`);
}
// settings.js
export const color = 'red';
// main.js
import { setAnimal } from 'A';
import { print } from 'B';

print();
setAnimal('cat');
print();

CodePudding user response:

import {farm} from 'A';
import {print, initialize as initialize_b} from 'B';

import {farm} from '/A.js';   /* It works by me to put a slash and .js at the end of doc name */
import {print, initialize as initialize_b} from '/B.js';

/*
const COLOR = 'red';

initialize_b({farm, COLOR});

export {farm, print, COLOR};
*/

  • Related