为什么更改组件属性的值会自动更改相应的服务属性?

时间:2019-04-03 03:02:58

标签: angular angular2-services

我正在开发一个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"}

  }

}

在组件中,通过调用testService.getData()方法在ngOnInit中初始化testComponentData属性,该方法返回this.serviceData.slice()

在此示例中,我单击第三个按钮将fname设置为“ Bartholomew”。正如您在嵌入式注释中看到的那样,即使我仅更改组件对象(testComponentData),testService数据也会更改,服务数据也将更改(this.testService.getData())

超时就在那儿,因为有时第一个console.log太慢,log会显示值已经更改。

我一辈子都看不到这是怎么回事。我知道这里有一些基本知识,我想我正在以某种方式访问​​同一对象,但是我不明白为什么。

感谢您的帮助。谢谢!

3 个答案:

答案 0 :(得分:1)

由于对象的相同引用,对象将更改。现在,如果您不想影响原始对象,则需要克隆。尝试遵循代码

声明克隆数组:

clonedTestComponentData: TestObject[];

克隆数组:

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

克隆对象:

const temp = Object.assign({}, this.testComponentData.find(o => o.id === id));

答案 1 :(得分:0)

这是因为在对象数组上的Array.slice正在创建一个新数组,其值是对原始对象的引用。您将不会看到带有字符串或数字数组之类的功能。您可以从this answer获取有关浅拷贝数组的更多信息。

答案 2 :(得分:0)

.slice()调用是复制数组的已知快捷方式。类似于使用传播[...someArray]运算符。但是,由于数组的内容是对象,因此它们通过引用返回到新数组中。

  

基本上,两个数组,即服务中的serviceData和服务中的temp   组件共享相同的对象引用。

因此,更新temp中一项的值也反映在serviceData数组中。