为什么我的Singleton模块似乎有两个实例?

时间:2019-05-27 15:40:45

标签: javascript node.js singleton getter-setter

问题

我正在尝试创建一个Singleton,该Singleton存储只能使用Setter和Getters访问的信息。我希望代码尽量简短简洁,因此我一直在寻找最短的编写方式。虽然这在大多数地方都行得通,但在其他地方,我倾向于制造一些对我来说无法解释的错误。

因此,..导入模块进行测试时,我使用:

const { ports, instance: activeConfig } = require('./activeConfig')

ports应该是我的Getter。我想避免在可能的情况下总是写出activeConfig.ports。我认为在很大程度上,这一直在我的测试中起作用,直到我尝试重置我的值为止。

我观察到的几件事:

  1. 运行activeConfig.ports时,我的吸气剂被激活。我可以在记录结果1、2和3之前看到它。
  2. 仅运行ports时,我的吸气器未激活。从日志结果1a,2a和3a中可以看到,在Singleton内部没有任何运行。但我仍然得到结果。
  3. 设置新值后,我可以在Singleton中看到_myPorts的值确实发生了变化。两种方法的结果也与我预期的一样。

但是,在重置我的值后,此行为不再保持一致。尽管activeConfig.ports提供了预期的结果,但ports没有提供。我不确定日志3a从何处获得此结果以及为什么它与日志结果3不同。

我显然内置了某种不稳定因素,但是我的JavaScript技能不足以查明问题所在。我尝试搜索“ JavaScript Singleton Getter Export”的所有变体,但似乎找不到涵盖我的特定用例的示例。

如果有人可以帮助我修复我的代码,将不胜感激。此外,将不胜感激,例如正确的术语或指向高级示例的链接。 :)

我的主要重点是能够在单个require命令中导入吸气剂!
我已经简化了这个示例,但是我希望能够使用x个吸气剂来做到这一点。

我不是在寻找类似的解决方法

const activeConfig = require('./activeConfig')
const ports = activeConfig.ports

const ports = require('./activeConfig').ports

这将需要每个吸气剂一行,我正试图避免这种确切的情况。 (尤其是10个以上的吸气剂)

我真的很想知道这样做是否正确。 :)

代码

'use strict'
let activeConfig = (function () {
  const _defPorts = {
    http: 80,
    https: 443,
    secure: false
  }

  let _myPorts = {..._defPorts}

  let _setPorts = function (value) {
    console.log('SP->', _myPorts)
    if (value) {
      Object.keys(value).forEach((key) => {
        if (typeof _myPorts[key] !== 'undefined') {
          _myPorts[key] = value[key]
        }
      })
    }
    console.log('SP=>', _myPorts)
  }

  let _resetConfig = function () {
      console.log('RC->', _myPorts)
      _myPorts = {..._defPorts}
      console.log('RC=>', _myPorts)
    }


  return {
    setPorts: _setPorts,
    resetConfig: _resetConfig,
    get instance() {
      return activeConfig 
    },
    get ports() {
      console.log('GP->', _myPorts)
      return _myPorts
    },
    set ports(value) {
      return _setPorts(value)
    }
  }
})()
module.exports = activeConfig

测试代码

'use strict'
const {
    ports,
    instance: activeConfig
} = require('./activeConfig')

console.log('1 ->', activeConfig.ports)
console.log('1a->', ports)
activeConfig
    .setPorts({
        secure: true,
        http: 8080
    })

console.log('2 ->', activeConfig.ports)
console.log('2a->', ports)
console.log('RESET')
activeConfig.resetConfig()
console.log('3 ->', activeConfig.ports)
console.log('3a->', ports)

日志

GP-> { http: 80, https: 443, secure: false }
GP-> { http: 80, https: 443, secure: false }
1 -> { http: 80, https: 443, secure: false }
1a-> { http: 80, https: 443, secure: false }
SP-> { http: 80, https: 443, secure: false }
SP=> { http: 8080, https: 443, secure: true }
GP-> { http: 8080, https: 443, secure: true }
2 -> { http: 8080, https: 443, secure: true }
2a-> { http: 8080, https: 443, secure: true }
RESET
RC-> { http: 8080, https: 443, secure: true }
RC=> { http: 80, https: 443, secure: false }
GP-> { http: 80, https: 443, secure: false }
3 -> { http: 80, https: 443, secure: false }
3a-> { http: 8080, https: 443, secure: true }

1 个答案:

答案 0 :(得分:1)

对象解构只是围绕属性访问的语法糖:

 const { port } = obj;
 // equals
 const port = obj.port;

因此,在您进行销毁时,您确实可以访问吸气剂。更改port会更改局部变量。它不会反射到对象,因此不会触发设置器。

没有以这种方式使用getters / setter方法的真正方法(好吧,让我们忘记with)。

相反,您可以手动触发虚幻的设置器:

  const obj = {
    port: { set(_v) { return this._v = _v; }, get() { return this._v; } }
  };

 const { port } = obj;
 port.set(10);