javascript: заставить фабричный элемент отображать правильное значение в поле, содержащем набор музыкальных альбомов - PullRequest
0 голосов
/ 23 января 2019

"singerAlbum" и "musicCollection" являются объектами. Сеттер альбомов в musicCollection предназначен для создания новых певческих альбомов. Проблема заключается в том, что при создании двух отдельных musicCollections и создании singerAlbum в одном из musicCollections он также появляется во втором musicCollection, хотя он там не был добавлен. код (javascript):

let singerAlbum = {
  Name: undefined,
  get name() {
    return this.Name;
  },
  set name(value) {
    this.Name = value;
  }
};

let musicCollection = {
  Name: undefined,
  Albums: new Set(),
  get name() {
    return this.Name;
  },
  get albums() {
    return this.Albums;
  },
  set name(value) {
    this.Name = value;
  },
  set albums(value) {
    let album = createSingerAlbum();
    album.name = value;
    musicCollection.Albums.add(album);
  },
};

function createSingerAlbum() {
  return Object.create(singerAlbum);
}

function createMusicCollection() {
  return Object.create(musicCollection);
}



let collection1 = createMusicCollection();
let collection2 = createMusicCollection();
collection1.albums = "Abbey Road";
console.log(collection1.albums);
console.log(collection2.albums);

Результат:

Set {Object {Name: "Abbey Road"}}
Set {Object {Name: "Abbey Road"}}

Результат, которого я хочу достичь:

Set {Object {Name: "Abbey Road"}}
Set {}

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Object.create дает новый объект с объектом, который вы передаете ему, установлен как прототип нового объекта. Если объект не имеет своего собственного свойства, установленного со значением, он использует значение из своего прототипа. Это именно то, что здесь происходит.

Кроме того, программа установки альбомов устанавливает значение непосредственно на musicCollection (прототип), но вы, вероятно, хотели установить значение на this (текущий объект).

Но поскольку вы изменяете существующий объект (альбомы) и поскольку каждый объект коллекции использует объект Albums прототипа вместо своего собственного, эти изменения будут изменены во всех объектах коллекции, созданных с помощью createMusicCollection.

Чтобы обойти это, вам нужно создать новый объект Albums для каждого объекта коллекции. Вот где конструкторы пригодятся. Обычно вы используете синтаксис class и определяете метод constructor, чтобы сделать это при создании объекта с new. Но так как вы используете фабричные методы, мы можем сделать это там. Вот как я бы порекомендовал изменить ваш код, если вы хотите продолжать использовать Object.create:

let singerAlbum = {
  Name: undefined,
  get name() {
    return this.Name;
  },
  set name(value) {
    this.Name = value;
  }
};

let musicCollection = {
  Name: undefined,
  // since we need to make a new album object each instance, don't make it here
  Albums: undefined, 
  get name() {
    return this.Name;
  },
  get albums() {
    // we could check to see if `this.Albums` is defined before returning it,
    // but let's create it in the "constructor" method instead
    return this.Albums;
  },
  set name(value) {
    this.Name = value;
  },
  set albums(value) {
    let album = createSingerAlbum();
    album.name = value;
    this.Albums.add(album);
  },
};

function createSingerAlbum() {
  return Object.create(singerAlbum);
}

function createMusicCollection() {
  let collection = Object.create(musicCollection);
  collection.Albums = new Set();
  return collection;
}



let collection1 = createMusicCollection();
let collection2 = createMusicCollection();
collection1.albums = "Abbey Road";
//modified to print a bit nicer in the snippet viewer
console.log("collection1:", ...collection1.albums); 
console.log("collection2:", ...collection2.albums);

Как правило, единственными вещами, которые вы хотите определить в своем прототипе, являются неизменяемые объекты, такие как функции и строки, числа и т. Д. Массивы, объекты, наборы, карты и т. Д. Являются изменяемыми, и если вы планируете мутируя их, вы, вероятно, захотите разные копии для каждого экземпляра объекта.

Смотри также:

0 голосов
/ 23 января 2019

Вот как бы я подошел к этому.

class Album {
  constructor(name, artist) {
    this.name = name
    this.artist = artist
  }
}

class Collection {
  constructor(name) {
    this.name = name;
    this.albums = new Set()
  }
  addAlbum(name, artist) {
    this.albums.add(new Album(name, artist))
  }
}

const bettlesCollection = new Collection('Bettles Collection')
bettlesCollection.addAlbum('Abbey Road', 'The Beetles')
bettlesCollection.addAlbum('Sgt. Pepper...', 'The Beetles')

console.log(bettlesCollection)
...