用空原型替换对象

Replacing an object with an empty prototype

我正在尝试通过将其完全替换为具有一组空值键的对象来刷新一些数据。

例如

const sportPrototype = {
  name: '',
  players: '',
  displacement: '',
  points: '',
  leagues: []
}

var profileScratchpadOne = {
  sportScratchpad: {
    name: 'Soccer',
    players: '16',
    displacement: 'Foot',
    points: 'unlimited',
    leagues: ["Fifa"]
  }
}

profileScratchpadOne.sportScratchpad = sportPrototype
profileScratchpadTwo.sportScratchpad = sportPrototype

每当 sportScratchpad 中的一个值发生变化时,profileScratchpadOneprofileScratchpadTwo 中的值都会发生变化。

我认为正在传递引用。

我研究了传播运算符、原型、构造函数,但尚未找到一种可靠、简洁的方法。

解决这个问题并每次都传递一个新对象的最简洁的方法是什么?

编辑:由于sportPrototype 上至少有一个对象(数组),浅拷贝在这里不是正确的选择。可以选择最简单的深层复制:

function deepCopy(o) {
  return JSON.parse(JSON.stringify(o));
}

const sportPrototype = {
  name: '',
  players: '',
  displacement: '',
  points: '',
  leagues: []
}

var profileScratchpadOne = {
  sportScratchpad: {
    name: 'Soccer',
    players: '16',
    displacement: 'Foot',
    points: 'unlimited',
    leagues: ["Fifa"]
  }
}

profileScratchpadOne.sportScratchpad = deepCopy(sportPrototype);
profileScratchpadTwo.sportScratchpad = deepCopy(sportPrototype);

正如其他人所提到的,Object.assign() 是创建对象浅表副本的一种方法。另一种选择是使用 Object.create(),其中 "wraps" 对象,以便为新对象的属性赋值不会覆盖原型的属性:

const sportPrototype = {
  name: '',
  players: '',
  displacement: '',
  points: '',
  leagues: []
}

var profileScratchpadOne = {
  sportScratchpad: {
    name: 'Soccer',
    players: '16',
    displacement: 'Foot',
    points: 'unlimited',
    leagues: ["Fifa"]
  }
}

var profileScratchpadTwo = {}

profileScratchpadOne.sportScratchpad = Object.create(sportPrototype)
profileScratchpadTwo.sportScratchpad = Object.create(sportPrototype)

console.log(sportPrototype.name);
console.log(profileScratchpadOne.sportScratchpad.name);
console.log(profileScratchpadTwo.sportScratchpad.name);

profileScratchpadOne.sportScratchpad.name = 'Jai Alai'
profileScratchpadTwo.sportScratchpad.name = 'Curling'

console.log(sportPrototype.name);
console.log(profileScratchpadOne.sportScratchpad.name);
console.log(profileScratchpadTwo.sportScratchpad.name);

但是,Object.createObject.assign 都会遇到 leagues 属性 的问题,因为它是引用类型,因此将在所有副本之间共享,如果你改变它(通过添加元素等)。出于这个原因,当您想要复制原型时,您基本上需要为 leagues(以及任何其他 reference-type 属性)创建一个新的空数组。

您可以使用工厂函数来解决这个问题,例如:

function sportDefaults() {
    var newObj = Object.create(sportPrototype);
    newObj.leagues = [];

    return newObj;
}

profileScratchpadOne.sportScratchpad = sportDefaults()

编辑: Object.create 的好处是原始原型只有一个副本,并且会根据需要创建新属性,从而节省内存。如果您不是那么关心内存,您可以创建一个函数,每次 returns 一个全新的原型副本。这将回避引用类型的 above-mentioned 问题:

function sportDefaults() {
  return {
    name: '',
    players: '',
    displacement: '',
    points: '',
    leagues: []
  }
}

var profileScratchpadOne = {}
var profileScratchpadTwo = {}

profileScratchpadOne.sportScratchpad = sportDefaults()
profileScratchpadTwo.sportScratchpad = sportDefaults()

console.log('- before assignment')
console.log(profileScratchpadOne.sportScratchpad.name)
console.log(profileScratchpadTwo.sportScratchpad.name)

profileScratchpadOne.sportScratchpad.name = 'Jai Alai'
profileScratchpadTwo.sportScratchpad.name = 'Curling'

console.log('- after assignment')
console.log(profileScratchpadOne.sportScratchpad.name)
console.log(profileScratchpadTwo.sportScratchpad.name)

虽然 Object.assign 可以在这里工作,但对象仍将共享相同的 leagues 数组。只有 primitive-typed 属性将过着单独的生活。您可以找到执行深层复制的函数,但我认为在这种情况下您可以使用构造函数模式:

function SportPrototype() {
  this.name = '';
  this.players = '';
  this.displacement = '';
  this.points = '';
  this.leagues = [];
}

var profileScratchpadOne = {};
var profileScratchpadTwo = {};

var o = new SportPrototype();
o.name = 'Soccer';
o.players = '16';
o.displacement = 'Foot';
o.points = 'unlimited';
o.leagues = ["Fifa"];
profileScratchpadOne.sportScratchpad = o;

profileScratchpadOne.sportScratchpad = new SportPrototype();
profileScratchpadTwo.sportScratchpad = new SportPrototype();

现在最后两个赋值将产生完全独立的对象。