Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid exporting singleton in es6

As I have seen, ES6 exports singletons for object literals:

// module A
export const singleton = {
  user: 'a',
  asd: 'b'
}

setTimeout(() => console.log(singleton.user), 5000) // 'asd'

// module B
import { singleton } from './A'
singleton.user = 'asd'

ie: if I change the A exports in B, it's also changed in A and in all modules that import A So, I wanted A to export a new instance of the object instead of a singleton, and I did this:

// module A
export const getObject = () => ({ user: 'asd', asd: 'b' })

That works, but I was thinking, is there a cleaner way to export new instances? Or the only way is exporting that function that I should call in B to get my new instance?

I think I can do this too, but it doesn't convince me:

// module A
export const getObject = (() => ({ user: 'asd', asd: 'b' }))()

Thanks

like image 999
Lucas Janon Avatar asked Dec 18 '22 22:12

Lucas Janon


2 Answers

ES module is evaluated only once on first import, this efficiently makes module exports singletons.

export const getObject = () => ({ user: 'asd', asd: 'b' })

is factory function and it's perfectly valid in this case, it's preferable for data-only object that has no inheritance and no methods.

A class is a suitable alternative (a bit less efficient than factory function but a better choice if there are methods):

export class A {
  constructor() {
    this.user =  'asd';
    this.asd = 'b';
  }
}

Since React is in use, it's safe to assume that the code is transpiled with Babel, so class fields proposal can be used. They aren't available in ES6 and provide syntactic sugar for constructor code listed above:

export class A {
  user = 'asd';
  asd = 'b';
}
like image 54
Estus Flask Avatar answered Dec 26 '22 00:12

Estus Flask


When a module is loaded, it is cached. So, when someone else loads it again, no new code is run. The previous exports are just returned.

That works, but I was thinking, is there a cleaner way to export new instances? Or the only way is exporting that function that I should call in B to get my new instance?

If you want a new instance each time, you have to export a function that you can call to get a new instance. There is no other way because loading a previously loaded module does not run any additional code - it just returns the previous cached exports.

You can either export a factory function (like in your example):

export const myFactory = function() {
   return { user: 'asd', asd: 'b' };
}

Or you can export a constructor function (that the caller would call with new to get a new object).

export class myObj {
   constructor() {
       this.user = 'asd';
       this.asd = 'b';
   }
   checkUser() {
       // some code here that operates on instance data
   }
}

Either the factory function or the constructor function would work just fine. If there are no methods and you just want a plain object, then the factory function is simpler. If there are methods, then the class probably makes more sense.

like image 22
jfriend00 Avatar answered Dec 25 '22 22:12

jfriend00