【问题标题】:Shared service is passing object by reference共享服务通过引用传递对象
【发布时间】:2020-02-13 02:43:23
【问题描述】:

您好,我遇到了 Angular 共享服务的问题。当我的应用程序启动时,会调用 init 函数并返回一些在整个应用程序中使用的数据。

组件可以注入此服务并获取数据,但数据可以在组件内部更改。通过我的实现,每次我更改组件内的对象时,从我的共享服务返回的对象也会更新。

@Injectable()
export class SharedDataService {
   private _object1: SomeType[];
   private _object2: SomeType[];
   private _object3: SomeType[];
   constructor(private _http: HttpClient, @Inject('BASE_URL') private _baseUrl: string) {}

   public init() {
       this._http.get<IInitModel>(this._baseUrl + 'init').subscribe(
            (r: IInitModel) => {
                this._object1 = r.object1;
                this._object2 = r.object2;
                this._object3 = r.object3;
            }
   }

   public getObject1(){
       return this._object1;
   }

   public getObject2(){
       return this._object2;
   }

   public getObject3(){
       return this._object3;
   }

函数 init() 在应用程序启动时被调用并获取一些跨应用程序所需的数据,在我的组件中我访问这些数据如下:

export class SomeComponent {
    public object1: SomeType[];
    constructor(private _sharedDataService: SharedDataService) {}
    ngOnInit() {
       this.object1 = this._sharedDataService.getObject1();
    }
}

如果我在组件内更改 ngOnInit 中的对象

this.object1.push({ prop1: 1, prop2: "SomeValue" })

共享服务中私有成员的值也会改变。

console.log(this._object1) // In shared service returns: [{ prop1: 1, prop2: "SomeValue"}]
console.log(this.object1) // In a component injecting the service: [{ prop1: 1, prop2: "SomeValue"}]

这是预期的行为吗?在返回对象时是否像我在服务中所做的那样通过引用传递对象。

有人可以推荐一个更好的方法来实现这个

【问题讨论】:

  • 是的,这是预期的行为。就像在 javascript 中一样。您应该克隆或创建对象的副本。
  • 请注意,对于所有三个getObject methods,您的SharedDataService 始终返回object1
  • @uminder,是的,只是我编辑了帖子的一个错字。谢谢。

标签: angular typescript


【解决方案1】:

在 javascript 中,对象和数组被设置为引用。

例如:

const obj1 = { name: 'Surjeet' }; // You have obj1 with name property
const obj2 = obj1; // assigning, it will set the reference of obj1 to obj2
obj2.name = 'Yuvi'; // now change obj2.name, it will also change obj1.name
console.log(obj1.name) // It prints Yuvi
console.log(obj1.name) // It also prints Yuvi

因此,在这种情况下,您必须制作对象的深层副本。所以你可以使用spread operator or lodash

使用扩展运算符

const arr = [1,2,3,4]
const copiedArr = [...arr];

使用 Lodash

const arr = [1,2,3,4]
const copiedArr = _.cloneDeep(arr);

所以在你的情况下像下面这样改变它

export class SomeComponent {
    public object1: SomeType[];
    constructor(private _sharedDataService: SharedDataService) {}
    ngOnInit() {
         this.object1 = _.cloneDeep(this._sharedDataService.getObject1());

         //OR

         //this.object1 = [...this._sharedDataService.getObject1()]; 
    }
}

【讨论】:

    【解决方案2】:

    您可以使用 lodash 来克隆您的对象。

    https://lodash.com/docs/4.17.15#cloneDeep

    @Injectable()
    export class SharedDataService {
       private _object1: SomeType[];
       private _object2: SomeType[];
       private _object3: SomeType[];
       constructor(private _http: HttpClient, @Inject('BASE_URL') private _baseUrl: string) {}
    
       public init() {
           this._http.get<IInitModel>(this._baseUrl + 'init').subscribe(
                (r: IInitModel) => {
                    this._object1 = r.object1;
                    this._object2 = r.object2;
                    this._object3 = r.object3;
                }
       }
    
       public getObject1(){
           return _.cloneDeep(this._object1);
       }
    
       public getObject2(){
           return _.cloneDeep(this._object1);
       }
    
       public getObject3(){
           return _.cloneDeep(this._object1);
       }
    }
    

    你也可以使用Object.assign(target, ...sources)这个方法用于将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

    【讨论】:

      猜你喜欢
      • 2017-12-21
      • 1970-01-01
      • 1970-01-01
      • 2017-09-11
      • 1970-01-01
      • 2011-07-06
      • 2012-07-07
      • 2012-01-05
      相关资源
      最近更新 更多