Angular7:服务实例工作不正常

Angular 7: Service instance working incorrectly

我的应用程序中有两个组件 - 'filter' 和 'home'。这两个组件是 app 组件的子组件。

我有一个以下对象,我想通过服务将其类型从过滤器组件传递到主组件。由于我希望此数据在过滤器组件中发生更改时在主组件中更新,因此我在服务中使用了 BehaviorSubject。

型号:过滤器-response.model.ts

export interface FilterResponse{
    filter:string;
    filterlist:string[];
}

filter.component.ts

export class FilterComponent implements OnInit {
    filterMainList:FilterResponse[]=[
        {
            "filter": "abc",
            "filterlist": ["a","b","c"]
        },
        {
            "filter": "def",
            "filterlist":["d","e","f"]
        },
        {
            "filter": "ghi",
            "filterlist": ["g","h","i"]
        }
    ];
    constructor(private filterService:FilterService,) {
        this.filterService.setFilterConditions(this.filterMainList);
    }
    ngOnInit() {
    }
}

在 home 组件中,我收到了数据,我想对其进行一些更改。

home.component.ts

export class HomeComponent implements OnInit {
  constructor(private filterService:FilterService) {
    this.filterService.getFilterConditions().subscribe((data)=>{
      let tc:FilterResponse[]=data
      for(let f in tc){
        tc[f].filterlist=['changes'];//this is where I make the changes
      }
    });
   }
  ngOnInit() {
  }
}

我有一个具有行为主题的过滤服务。这就是我感到困惑的地方。我在 next() 之前在服务中记录数据,而我实际得到的数据是我在 home 组件中更改的数据,这意味着我对 home 组件中的数据实例所做的更改也会影响(更改)的实例服务中的数据。

filter.service.ts

@Injectable({
    providedIn:'root'
})
export class FilterService{
    private filterConditions = new BehaviorSubject<FilterResponse[]>(null);
    constructor(){}
    setFilterConditions(filterList:FilterResponse[]){
        console.log(filterList);//data changes incorrectly
        this.filterConditions.next(filterList);
    }
    getFilterConditions():Observable<FilterResponse[]>{
        return this.filterConditions.asObservable();        
    }
}

我的控制台日志:

实际上应该是我刚刚传入过滤器组件的数据。但是它显示了我在home组件中修改的数据。

最后 app.component.ts,如果有帮助的话

app.component.ts

<app-filter></app-filter>
<app-home></app-home>

我想提请您注意的另一件事是。我试图在 stackblitz 中重新创建场景。但问题是它在那里工作得很好。

https://stackblitz.com/edit/angular-ivy-9th5pj

请解释一下我的项目中缺少什么。或者这是服务在 angular.

中的实际工作方式

在您的服务文件中进行此更改

 setFilterConditions(filterList:FilterResponse[]){
    this.filterConditions.next(JSON.parse(JSON.stringify(filterList)));
}

这将克隆您的阵列。还有许多其他方法也可以在 JS 中克隆 object/array Different ways to Clone object in JS

原因:

在 TS 中,当将对象作为函数参数传递时,您传递的是对该对象的引用。因此,当修改传递给函数的对象时,您正在修改该原始对象。

同样在HomeComponent的订阅函数中接收到的array/object是引用接收的。因此 HomeComponent 中的值更改也会影响服务。

我误解了你的问题:我认为你的问题是为什么 console.log 输出显示修改后的数组,同时放置在 修改之前。

中解释的那样,非基本类型通过引用传递:JS不会将数组的副本传递给functions/methods,而是数组本身。因此,这是通过 next 传递的相同数组实例 (filterMainList),并在您的 HomeComponent.

中进行了修改

现在,您有 console.log(filterList) 之前的数据修改,但日志输出仍然显示更改。这是因为当您在浏览器的控制台中单击 Array(3) 时,调试器会评估此时变量的值,此时该值已被修改。

这在您的 stackblitz 示例中不可见,因为您没有记录数组,但是 JSON.stringify(arr)。在这种情况下,您不需要在控制台中扩展该值,该值已经显示为字符串并且不会重新计算。 如果我们只记录变量,stackblitz demo 将重现相同的 'problem'

如果这种行为不是您想要的,您可以按照 khush 的建议克隆传递的数据;从发送它的组件,或者在调用 next 之前直接在您的服务中,如果您的代码中多次调用 setFilterConditions

,您只需执行一次

我将扩展 Khush 的回答。因此,如果创建深层副本没有任何效果,那么您可以从 loadash 中获取 cloneDeep 函数。请在最坏的情况下使用此选项(修补程序问题)。 此问题是由于浅拷贝而发生的。 因此,当您在每种情况下返回数组时,您返回的不是新数组,而是数组的地址。因此,无论数组发生什么变化,原始数组都会发生变化。当您使用 JSON.stringigy 或 deepClone 函数时,您会在内部创建具有不同地址

的数组副本
setFilterConditions(filterList:FilterResponse[]){
    this.filterConditions.next(cloneDeep(filterList));
}