@ObservedV2与@Trace装饰的对象key都带有\_\_ob\_导致反序列化异常
=============================================

#### 问题现象

@ObservedV2与@Trace装饰的对象key都带有\_\_ob\_导致反序列化出现异常，无法反序列化。

"dateTimeGroup": {
    "\_\_ob\_beginDate": "2024-06-05",
    "\_\_ob\_beginTime": "17:00",
    "\_\_ob\_endDate": "2024-06-07",
    "\_\_ob\_endTime": "17:00"
}

#### 背景知识

*   状态管理V2装饰器会为装饰的变量生成getter和setter方法，同时为原有变量名添加\_\_ob\_的前缀，出于性能考虑，官方提供的[getTarget接口](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-gettarget)并不支持获取@ObservedV2与@Trace装饰的原对象，详情请参考官方文档：[获取状态管理V2代理前的原始对象](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-gettarget#获取状态管理v2代理前的原始对象)。
*   @ObservedV2的类实例无法直接使用JSON.parse反序列化获得（直接使用JSON.parse反序列化获得的对象无法观察属性变化），详情请参考[使用限制](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace#使用限制)。

#### 解决方案

\_\_ob\_前缀无法避免，且前缀不影响对象属性的getter和setter方法使用。如果涉及序列化与反序列化，可通过如下示例方法，将前缀去除。

*   **方案一**：创建一个新的类，类中属性名和原来的对象相同，用原来对象的值来初始化新类的对象。
    
    @ObservedV2
    class FormDataClassV2 {
      @Trace name: string = '默认名称';
      @Trace price: number = 0;
    }
    
    class FormDataClass {
      name: string = '';
      price: number = 0;
    
      constructor(v: FormDataClassV2) {
        this.name = v.name;
        this.price = v.price;
      }
    }
    
    @Entry
    @ComponentV2
    struct FormDataClassPage {
      @Local data: FormDataClassV2 = new FormDataClassV2();
    
      build() {
        Column() {
          Button('序列化')
            .onClick(() => {
              console.info('序列化原始值：', JSON.stringify(this.data));
              console.info('序列化转换后：', JSON.stringify(new FormDataClass(this.data)));
            });
        }
        .height('100%')
        .width('100%');
      }
    }
    

*   **方案二**：序列化后\_\_ob\_前缀会导致反序列化异常，可以考虑采用修改序列化后的字符串的方式，去除\_\_ob\_前缀。实现方式如下：
    
    @ObservedV2
    class FormDataClassV2 {
      @Trace name: string = '默认名称';
      @Trace price: number = 0;
    }
    
    @Entry
    @ComponentV2
    struct FormDataClassPage {
      @Local data: FormDataClassV2 = new FormDataClassV2();
    
      build() {
        Column() {
          Button('序列化')
            .onClick(() => {
              console.info('序列化原始值：', JSON.stringify(this.data));
              let newData = JSON.stringify(this.data).replace(/\_\_ob\_/g, '');
              console.info('序列化过滤后：', newData);
            });
        }
        .height('100%')
        .width('100%');
      }
    }
    

#### 常见FAQ

Q：如何获取@ObservedV2与@Trace装饰的原始对象？

A：去除\_\_ob\_前缀后，使用JSON.prase反序列化即可，此时反序列化后的原始对象没有深度观测的能力。

Q：如何使反序列化后的对象可观测？

A：若需要序列化后的对象可观察，详情可参考官方文档：[@ObservedV2装饰对象的序列化与反序列化](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace#observedv2装饰对象的序列化与反序列化)，或使用[makeObserved接口：将非观察数据变为可观察数据](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-makeobserved)。

Q：getTarget接口的使用场景有哪些？

A：getTarget可以获取代理对象的原始对象，修改原始对象数据，不会触发UI刷新。

使用场景如下：

*   类型比较或者序列化场景，需要获取原始对象。
*   三方库集成场景，需要传原始对象数据。
*   大量修改数据场景，如数据排序等，对原始对象操作避免代理层性能开销。