代码之家  ›  专栏  ›  技术社区  ›  Lucas Janon

避免在es6中导出singleton

  •  3
  • Lucas Janon  · 技术社区  · 6 年前

    如我所见,ES6为对象文本导出单例:

    // 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:如果我在B中更改A导出,它在A中也会更改,并且在所有导入A的模块中都会更改 所以,我希望a导出对象的新实例,而不是单例,我这样做了:

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

    这很有效,但我在想,有没有一种更干净的方法来导出新实例?或者唯一的方法是导出我应该在b中调用的函数来获取我的新实例?

    我想我也能做到,但这不能说服我:

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

    谢谢

    2 回复  |  直到 6 年前
        1
  •  5
  •   Estus Flask    6 年前

    ES模块在第一次导入时只评估一次,这有效地使模块导出单例。

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

    是工厂函数,在本例中完全有效,对于没有继承和方法的纯数据对象更可取。

    类是一个合适的替代方法(比工厂函数效率低一点,但如果有方法,则是一个更好的选择):

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

    因为react正在使用,所以可以安全地假设代码是用babel传输的,所以 class fields 建议可以使用。它们在ES6中不可用,并为上面列出的构造函数代码提供语法糖:

    export class A {
      user = 'asd';
      asd = 'b';
    }
    
        2
  •  2
  •   jfriend00    6 年前

    加载模块时,将对其进行缓存。所以,当其他人再次加载时,不会运行新代码。以前的出口货物刚刚退回。

    这很有效,但我在想,有没有一种更干净的方法来导出新实例?或者唯一的方法是导出我应该在b中调用的函数来获取我的新实例?

    如果每次都需要一个新实例,则必须导出一个可以调用的函数以获取新实例。没有其他方法,因为加载以前加载的模块不会运行任何其他代码—它只返回以前缓存的导出。

    可以导出工厂函数(如示例中所示):

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

    或者可以导出构造函数(调用方将使用 new 以获取新对象)。

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

    工厂函数或构造函数都可以正常工作。如果没有方法,而您只需要一个普通的对象,那么factory函数更简单。如果有方法,那么这个类可能更有意义。