【问题标题】:javascript singleton how to change properties inside a classjavascript单例如何更改类中的属性
【发布时间】:2020-04-08 09:24:02
【问题描述】:

我看到人们使用Object.freeze 和其他一些技术来创建一个单例类。

假设我有这门课。

class Test {
    constructor(){
        this.data = [];
    }

    setData(){
        this.data = [1,2,3];
    }

}

const test = new Test();
Object.freeze(test);
export default test;

现在,我将它导入另一个文件。

import Test from './test'
Test.setData();

这现在会导致 Cannot assign to read only property to data 的错误,这意味着我什至不能对我的属性使用 setter/getter。

问题 1) 如果我们甚至不能更改类中的属性,为什么还要使用 Object.freeze

问题 2)我会怎么做才能不更改类外的属性,但要更改类内的属性?

【问题讨论】:

  • 这不是单例模式。 Object.freeze 的目标是使对象不可变。因此错误
  • 我个人会做 import test from './test' ,只是为了保持一致并在以后避免任何混乱..

标签: javascript oop design-patterns


【解决方案1】:

使用 Object.freeze

如果您尝试实现 here 中描述的某些内容。该方法与您在这里所做的不同之处在于您应该更新数据数组而不是完全重新分配它。由于Object.freeze 我们基本上执行了浅冻结,因此您可以在data 数组上推送和弹出,但不能重新分配它(这就是您在示例中所做的)。所以下面会起作用:

class Test {
    constructor(){
        this.data = [];
    }

    setData(data) {
        this.data.push(...data);
    }

}

const test = new Test();
Object.freeze(test);
export default test;

然后你可以像这样添加你的数据:

import Test from './test'
Test.setData(1,2,3);

私有属性

由于我了解您的目标是实际创建无法在单例之外更新的私有属性,因此您也可以遵循此答案 SO Answer 中概述的方法。在您的情况下,这将如下所示:

class Test {
    constructor(){
        let data = [];
        this.setData = (newData) => data = newData;
        this.getData = () => data;
    }
}

const test = new Test();
test.setData([1,2,3]);

console.log(test.getData());
由于数据字段没有直接公开,而是仅在您的构造函数范围内公开,因此更新或检索它的唯一方法是使用 setDatagetData,这就是您的目标。

【讨论】:

  • 你也可以setData(arr) { this.data.push( ...arr ) }
  • 所以,object.freeze 根本不是关于单例的。并且没有办法不能在类外更改值,而是在 javascript 中的类内更改值,对吧?
  • @Rajesh 很好的建议,我已经用你的例子更新了我的答案。
  • @NikaKurashvili Object.freeze 将不允许您在冻结后删除、添加或重新分配特定对象期间的任何属性。由于它很浅,您仍然可以按照您喜欢的方式更新底层数组。它不一定与单例模式有关
  • 我问的好像没有办法。
【解决方案2】:

如评论:

这不是单例模式。 Object.freeze 的目标是使对象不可变。因此出现错误。

单例:

这意味着一个类只能有一个跨应用程序共享的实例。通常,这意味着构造函数是私有的,并且执行new 会抛出错误。

但是,到目前为止,在 JS 中,您不能拥有私有构造函数。所以你可以试试这个方法:

想法:

  • 在编译期间,您将创建一个对象并存储它的引用。
  • 无论何时尝试创建它的实例,都会返回最初创建的对象的引用。这样,所有尝试都将指向同一个对象,也就是单例。

你不需要Object.freeze,除非你想让对象不可变。

class Test {
  static _instance = null;
  static getInstance() {
    return Test._instance || new Test();  
  }

  constructor() {
    this.data = [];
    if (Test._instance === null) {
      Test._instance = this;
      return this;
    }
    else return Test._instance;
  }
  
  setData(data) {
    this.data = data;
  }
}

const t1 = new Test();
const t2 = new Test();

t2.setData([1,2,3]);

console.log(t1.data, t2.data)

t1.setData('This is a test')

console.log(t1.data, t2.data)

【讨论】:

    猜你喜欢
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多