javascript : 使工厂项目在包含音乐专辑集的字段上显示正确的值

javascript : making a factory item display proper value on the field containing music albums set

"singerAlbum" 和 "musicCollection" 是对象。 musicCollection 中的 setter 专辑用于创建新歌手专辑。问题是:当创建两个不同的 musicCollection 并在其中一个 musicCollection 中创建一个 singerAlbum 时,它也出现在第二个 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 {}

这就是我的处理方式。

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)

Object.create 给出了一个新对象,你传递给它的对象被设置为新对象的原型。如果一个对象没有自己的 属性 设置值,它会使用其原型中的值。这正是这里发生的事情。

此外,您的相册 setter 直接在 musicCollection(原型)上设置值,但您可能想在 this(当前对象)上设置值.

但是由于您正在改变现有对象(Albums),并且因为每个集合对象使用原型的 Albums 对象而不是它自己的对象,所以这些更改将在使用 [=15 创建的所有集合对象中更改=].

为了解决这个问题,您需要为每个集合对象创建一个新的 Albums 对象。这就是构造函数派上用场的地方。通常,在使用 new 创建对象时,您会使用 class 语法并定义一个 constructor 方法来执行此操作。但是因为你使用的是工厂方法,我们可以在那里做。如果您想继续使用 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);

一般来说,你想在你的原型上定义的唯一东西是不可变的对象,比如函数和字符串、数字等。数组、对象、集合、映射等是可变的,如果你是计划改变它们,您可能需要为对象的每个实例创建不同的副本。

另请参阅: