Почему изменение значения свойства компонента автоматически меняет соответствующее свойство службы? - PullRequest
1 голос
/ 03 апреля 2019

Я работаю над приложением angular2, которое использует несколько сервисов для обмена данными по всему приложению.

В одной части моего приложения у меня есть функция редактирования, которая позволяет пользователю изменять данные в массиве.

В этом случае, когда пользователь изменяет свойство в компоненте, соответствующие данные в службе также изменяются без его непосредственной установки.

У меня около 6 месяцев на изучение углов, но я знаю, что установка одного массива равным другому фактически указывает на один и тот же объект. Так что в этом случае у меня есть метод в службе, который возвращает массив в виде slice (), который, как я считаю, должен создавать новый массив, чтобы пользователь не мог напрямую изменять данные службы.

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

test.component.html:

<div *ngFor="let item of testComponentData">
      <p>{{ item.fname }} {{ item.lname }} <button (click)="onUpdate(item.id)">Update</button></p>
</div>

test.model.ts:

export class TestObject {
  constructor(public id: string, public fname: string, public lname: string) {}

test.service.ts:

@Injectable()
export class TestService {

  constructor() { }


  private serviceData: TestObject[] = [
    new TestObject('1', 'Joe', 'Smith'),
    new TestObject('2', 'Mary', 'Jones'),
    new TestObject('3', 'Larry', 'Murray'),
  ];

  getData() {
    return this.serviceData.slice();
  }
}

test.component.ts:

export class TestComponent implements OnInit {
  testComponentData: TestObject[];

  constructor(private testService: TestService) { }

  ngOnInit() {
    this.testComponentData = this.testService.getData();
  }

  onUpdate(id) {

    // Clicked 3rd button, id = 3

    const temp = this.testComponentData.find(o => o.id === id);

    console.log(this.testService.getData());

    // 0: TestObject {id: "1", fname: "Joe", lname: "Smith"}
    // 1: TestObject {id: "2", fname: "Mary", lname: "Jones"}
    // 2: TestObject {id: "3", fname: "Larry", lname: "Murray"

    setTimeout(() => {
      temp.fname = 'Bartholomew';
      console.log(this.testService.getData());
    }, 5000);

    // 0: TestObject {id: "1", fname: "Joe", lname: "Smith"}
    // 1: TestObject {id: "2", fname: "Mary", lname: "Jones"}
    // 2: TestObject {id: "3", fname: "Bartholomew", lname: "Murray"}

  }

}

В компоненте свойство testComponentData инициализируется в ngOnInit путем вызова метода testService.getData (), который возвращает this.serviceData.slice ()

В этом примере я нажимаю третью кнопку, чтобы установить для fname значение «Варфоломей». Как вы видите во встроенных комментариях, данные testService изменяются, хотя я только меняю объект компонента (testComponentData), данные службы также меняются (this.testService.getData ())

Тайм-аут просто там, потому что иногда первый файл console.log запаздывает, и журнал показывает, что значение уже изменилось.

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

Любая помощь приветствуется. Спасибо!

Ответы [ 3 ]

1 голос
/ 03 апреля 2019

Объект изменится из-за той же ссылки на объект.Теперь нужно клонировать, если вы не хотите эффект исходного объекта.Попробуйте следующий код

Объявите массив клонов:

clonedTestComponentData: TestObject[];

Клонируйте массив:

const this.clonedTestComponentData  = Object.assign([], this.testComponentData);

Клонируйте объект:

const temp = Object.assign({}, this.testComponentData.find(o => o.id === id));
0 голосов
/ 03 апреля 2019

Пустой .slice() вызов - это известный ярлык репликации массива.Аналогично использованию оператора распространения [...someArray].Однако, поскольку содержимое массива является объектами, оно возвращается по ссылке в новый массив.

По сути, оба массива, т. Е. serviceData в службе и temp в компоненте, совместно используютте же ссылки на объекты.

Следовательно, обновление значения элемента в temp также отражается в массиве serviceData.

0 голосов
/ 03 апреля 2019

Это потому, что Array.slice в массиве объектов создает новый массив, значения которого являются ссылками на исходные объекты.Вы не увидите эту функциональность с чем-то вроде массива строк или чисел.Вы можете получить больше информации от этого ответа о мелком копировании массивов.

...