Класс против области действия экземпляра в JavaScript - PullRequest
3 голосов
/ 10 июля 2019

Я оцениваю способ использования шаблона Singleton под названием Monostate в JavaScript.

У меня есть код, подобный следующему:

class Boss {
  get name() { return Boss._name }
  set name(value) {
    Boss._name = value;
  }

  get age() { return Boss._age }
  set age(value) {
    Boss._age = value
  }

  toString() {
    return `
      Boss' name is ${this.name}
      and he is ${this.age} years old.
    `
  }
}

Boss._age = undefined;
Boss._name = undefined;

Но я не очень хорошо понимаю разницу между областью действия класса и областью действия экземпляра

Я имею в виду, если я сделаю следующее:

let boss = new Boss();
boss.name = 'Bob';
boss.age = 55;

let boss2 = new Boss();
boss2.name = 'Tom';
boss2.age = 33;

console.log(boss.toString());
console.log(boss2.toString());

Я всегда буду получать данные второго экземпляра с именем Tom, но почему?

Boss' name is Tom and he is 33 years old.

Ответы [ 3 ]

2 голосов
/ 10 июля 2019

Причина такого поведения заключается в том, что экземпляры Boss ссылаются на один и тот же объект Boss для установки и чтения своих значений.Экземпляры Boss устанавливают значения _name и _age на Boss.При чтении из этих атрибутов экземпляра возвращается последний набор значений.

Это можно увидеть по значению Boss._name, которое меняется каждый раз, когда экземпляр Boss устанавливает свое имя.После boss.name = 'Bob' значение Boss._name будет 'Bob'.После установки boss2.name = 'Tom' значение Boss._name будет 'Tom'.

Я добавил фрагмент, который, как мы надеемся, лучше отображает тревожное поведение.В приведенном ниже сценарии boss1 и boss2 имеют свое собственное хранилище, а boss3 и boss4 совместно используют свое хранилище (в качестве хранилища используется объект Boss).

class Boss {
  constructor(storage) {
    this.storage = storage || {};
  }
  
  get name() {
    return this.storage.name;
  }
  
  set name(value) {
    this.storage.name = value;
  }
}

var boss1 = new Boss(),
    boss2 = new Boss(),
    sharedStorage = {},
    boss3 = new Boss(sharedStorage),
    boss4 = new Boss(sharedStorage);

boss1.name = "a";
boss2.name = "b";
boss3.name = "c";
boss4.name = "d";

console.log(boss1.name, boss2.name, boss3.name, boss4.name);
0 голосов
/ 10 июля 2019

Используйте this вместо имени класса Boss для ссылки на экземпляр объекта из определения класса:

class Boss {
  get name() {
    return this._name
  }
  set name(value) {
    this._name = value;
  }

  get age() {
    return this._age
  }
  set age(value) {
    this._age = value
  }

  toString() {
    return `
      Boss' name is ${this.name}
      and he is ${this.age} years old.
    `
  }
}

const b1 = new Boss();
b1.name = 'Tom';
b1.age = 55;

const b2 = new Boss();
b2.name = 'Bill';
b2.age = 33;

console.log(b1.toString());
console.log(b2.toString());

Boss, на который вы ссылаетесь в своем коде, на самом деле является конструктором, когда вы действительно хотите экземпляр.

0 голосов
/ 10 июля 2019

Boss не ссылается на экземпляр класса, он ссылается на функцию конструктора Boss, которая является единственной во всем коде. В методах вы добавляете свойство не к экземпляру, а к конструктору.

Вам необходимо использовать this для доступа к экземпляру внутри метода объекта.

class Boss {
  get name() { return this._name }
  set name(value) {
    this._name = value;
  }

  get age() { return this._age }
  set age(value) {
    this._age = value
  }
}


let boss = new Boss();
boss.name = 'Bob';
boss.age = 55;

let boss2 = new Boss();
boss2.name = 'Tom';
boss2.age = 33;


console.log(boss2.name);

console.log(boss.name);
...