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));
}
我的应用程序中有两个组件 - '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
输出显示修改后的数组,同时放置在 修改之前。
如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));
}