javascript singleton, как изменить свойства внутри класса - PullRequest
1 голос
/ 08 апреля 2020

Я видел, что люди используют Object.freeze наряду с некоторыми другими методами, чтобы создать класс Singleton.

Допустим, у меня есть этот класс.

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, что означает что я даже не могу использовать сеттеры / геттеры для своих свойств.

Вопрос 1) почему мы используем Object.freeze, если мы не можем даже изменить свойства внутри класса?

Вопрос 2 ) что бы я сделал, чтобы иметь возможность изменять не свойства вне класса, а внутри класса?

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020

Использование Object.freeze

В случае, если вы пытались реализовать что-то, как описано здесь . Разница между этим подходом и тем, что вы здесь делаете, заключается в том, что вы должны обновлять массив данных, а не переназначать его полностью. Так как Object.freeze мы, по сути, выполняем мелкое замораживание, вам разрешается делать pu sh и вставлять массив 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 Ответ . В вашем случае это будет выглядеть следующим образом:

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());
Поскольку поле данных отображается не напрямую, а только в области видимости вашего конструктора, единственный способ обновить или извлечь его - использовать setData и getData, к чему вы стремились делаем.
1 голос
/ 08 апреля 2020

Как прокомментировано:

Это не шаблон Singleton. Цель Object.freeze - сделать объект неизменным. Отсюда ошибка.

Singleton:

Это означает, что класс может иметь только один экземпляр, который является общим для всего приложения. Обычно это означает, что конструктор является закрытым, и выполнение new приведет к ошибке.

Однако в JS на данный момент у вас не может быть частного конструктора. Таким образом, вы можете попробовать этот подход:

Идея:

  • Во время компиляции вы создадите объект и сохраните его ссылку.
  • Всякий раз, когда вы пытаетесь создать его экземпляр, вы вернете ссылку на изначально созданный объект. Таким образом, все попытки будут указывать на один и тот же объект, он же синглтон.

Вам не нужно Object.freeze, если только вы не sh сделаете объект неизменным.

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)
...