Есть ли способ скопировать массив объектов в javascript? - PullRequest
0 голосов
/ 24 апреля 2020

Это может быть проблема, вызванная моей некомпетентностью в javascript, так как я плохо знаком с языком, но до сих пор не нашел рабочего решения.

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

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

class Country{
    name; area; population;

    constructor(name, area, population){
        this.name = name;
        this.area = area;
        this.population = population;
    }

    changeData(){
        this.population += Math.round(this.population * 0.02);
    }
}

class World{
    countries = [];
    copyData = [];

    constructor(){
        this.loadData();
        this.copyData = this.countries.slice(0);
    }

    loadData(){
        this.countries.push(new Country("Denmark", 41990, 5839809));
        this.countries.push(new Country("Germany", 349360, 83159604));
        this.countries.push(new Country("Netherlands", 33690, 17342709));
    }

    changeAllCountriesData(){
        this.copyData.forEach(c => {
            c.changeData();
        })
    }
}
console.log("Initial information for the population: 5839809, 83159604, 17342709")
w = new World();
w.changeAllCountriesData();
console.log("countries array:")
console.log(w.countries);
console.log("copyData array:")
console.log(w.copyData);

Другие способы, которые я пробовал вместо this.copyData = this.countries.slice (0):

1.

this.copyData = [...this.countries]

2.

this.copyArray = Array.from(this.countries);
this.copyData = copyArray[0];

3.

this.countries.forEach(c => {
      this.copyData.push({...c});
})

Приведенный выше код возвращает NaN после каждого вычисления.

4.

this.countries.forEach(c => {
      let obj = Object.assign({}, c);
      this.copyData.push(obj);
})

5.

this.copyData = this.countries.concat();

Ни один из этих методов не создал массив копий таким образом, чтобы исходный массив оставался неизменным или вычисления выполнялись без возврата NaN.

Ответы [ 2 ]

1 голос
/ 24 апреля 2020

В JS объекты копируются с использованием ссылки. Поэтому, когда вы так .slice(0), вы частично правы, но проблема в том, что внутренние значения являются объектами. Таким образом, новый массив имеет предыдущие значения.

Теперь вы также можете попробовать .map(obj => ({ ...obj }) ), но это не сработает, поскольку распространение объекта создаст новый объект со свойствами, но не с методами. Таким образом, никакого метода, такого как changeData, на этом объекте не будет. Из-за этого вам нужно будет создать механизм копирования для вашего класса.

Попробуйте обновить до

cloneObject() {
  const {name, area, population} = this;
  return new Country(name, area, population)
}

...

this.copyData = this.countries.map( (obj) => obj.cloneObject() );

Примечание: Вы можете расширить возможности этой функции. Вы можете добавить аргумент для переопределения значений. Это позволит вам выполнять несколько операций за один go:

cloneObject( overrides ) {
  const { name, area, population } = { ...this, ...overrides };
  return new Country(name, area, population)
}

...

this.copyData = this.countries.map( (obj) => obj.cloneObject({ name: 'Hello World' }) );

Пример кода:

class Country{
    name; area; population;

    constructor(name, area, population){
        this.name = name;
        this.area = area;
        this.population = population;
    }
    
    cloneObject() {
      const {name, area, population} = this;
      return new Country(name, area, population)
    }

    changeData(){
        this.population += Math.round(this.population * 0.02);
    }
}

class World{
    countries = [];
    copyData = [];

    constructor(){
        this.loadData();
        this.copyData = this.countries.map( (obj) => obj.cloneObject() );
    }

    loadData(){
        this.countries.push(new Country("Denmark", 41990, 5839809));
        this.countries.push(new Country("Germany", 349360, 83159604));
        this.countries.push(new Country("Netherlands", 33690, 17342709));
    }

    changeAllCountriesData(){
        this.copyData.forEach(c => {
            c.changeData();
        })
    }
}
console.log("Initial information for the population: 5839809, 83159604, 17342709")
w = new World();
w.changeAllCountriesData();
console.log("countries array:")
console.log(w.countries);
console.log("copyData array:")
console.log(w.copyData);
0 голосов
/ 24 апреля 2020

Я собирался комментировать, но не смог, так как у меня еще недостаточно очков.

  1. В changeAllCountriesData() (внутри class World) вы пытаетесь вызвать changeDate() функция, которая является локальной функцией внутри класса Country. Я не уверен, что класс World может получить доступ к локальной функции другого класса напрямую. Вы можете вызывать функцию внутри класса после того, как вы присвоили класс переменной var, let или const. Пример:

    const codeland = new Country ('USA', 123, 456);

    codeland.changeData ();

Теперь кодовая земля является глобальной переменной. Теперь вы можете получить доступ к функции changeData () через переменную codeland в вашем классе World.

Я не профессионал в JavaScript, и, я считаю, должен быть более простой способ!

Что касается копирования массивов, методы # 1 и # 3 верны. (Не уверен насчет методов № 2 и № 4. Метод № 5 объединен countries в copyData.) Они возвращают NaN, потому что обе страны и copyData пусты, когда вы копируете данные из одного массива в другой. Следовательно, это NaN (или не определено).

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...