浅析如何使用JavaScript轻松实现数据转换

 更新时间:2024年10月24日 09:14:42   作者:Hamm  
这篇文章主要为大家详细介绍了如何使用JavaScript轻松实现数据转换,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

之前写了一篇 《TypeScript装饰器之我们是这么处理项目数据转换的》,有很多朋友私信和评论说,如果没有 TypeScript装饰器,纯 JavaScript 有没有什么好的数据转换的方案呢?

很遗憾,还真有,虽然没有 TypeScript 那么优雅,但是也足够好用。

这里用到了 Getter/Setter,以及 Object 原型链相关的知识。

一、假设需求

1. 后端返回的数据

这里我们先假设从后端来了个 JSON 长这样:

{
  id: 1,
  nickname: 'Hamm',
  age: 18,
  sex: 1,
  createTime: 1707021296000,
  bio: '一些废话,前端不需要的字段'
}

其中,id createTime 是固定返回的公共属性。

2. 前端类型声明

基类

class BaseEntity {
  id;
  createTime;
}

用户类

class User extends BaseEntity {
  nickname;
  age;
  sex;
}

3. 转换要求

转换到类时

  • createTime 转为 Date类型;
  • 前端使用 gender 作为性别字段,且需要根据 1/0 显示男女;
  • 前端没有 bio 字段,需要过滤掉。

转换到 JSON 时

  • createTime 转回后端需要的时间戳
  • gender 还原回后段需要的 sex,并且转换为 1/0

二、实现思路

正如我们之前有篇关于 几个有关Getter/Setter的小故事 文章中提到,我们可以用 getter/setter 来拦截数据达到转换数据的目的:

1. 基于基类实现 fromJson 静态方法

class BaseEntity {
  id;
  createTime;

  static fromJson(json) {
    const user = new this();
    const filteredJson = Object.keys(json).reduce((item, key) => {
      if (user.hasOwnProperty(key)) {
        item[key] = json[key];
      }
      if (user.__proto__.hasOwnProperty(key)) {
        item[key] = json[key];
      }
      return item;
    }, {});
    const entity = Object.assign(user, filteredJson);
    if (entity.createTime) {
      entity.createTime = new Date(entity.createTime);
    }
    return entity;
  }
}

class UserEntity extends BaseEntity {
  nickname;
  age;
  gender;
  get sex() {
    return this.gender;
  }
  set sex(value) {
    if (value === undefined || value === null) {
      this.gender = undefined
    }else{
      this.gender = value === 1 ? '男' : '女';
    }
  }
}

const json = {
  id: 1,
  nickname: 'Hamm',
  age: 18,
  sex: 1,
  createTime: 1707021296000,
  bio: '一些废话,前端不需要的字段'
}
console.log("json", json)
const user = UserEntity.fromJson(json)
console.log("entity", user)

其中,我们通过读取 getter/setter 以及本身的属性,来确定哪些是直接赋值,哪些是走set方法,哪些不存在的需要忽略。

2.调试输出,美滋滋

json {
  id: 1,
  nickname: 'Hamm',
  age: 18,
  sex: 1,
  createTime: 1707021296000,
  bio: '一些废话,前端不需要的字段'
}
entity UserEntity {
  id: 1,
  createTime: 2024-02-04T04:34:56.000Z,
  nickname: 'Hamm',
  age: 18,
  gender: '男'
}

3. 实现动态方法的 toJson

接下来,我们需要将 BaseEntity 添加一个 toJson 方法,用于将实体转换为 JSON 格式,且给 UserEntitysex getter 做一下数据转换:

class BaseEntity {
  id;
  createTime;

  static fromJson(json) {
    const user = new this();
    const filteredJson = Object.keys(json).reduce((item, key) => {
      if (user.hasOwnProperty(key)) {
        item[key] = json[key];
      }
      if (user.__proto__.hasOwnProperty(key)) {
        item[key] = json[key];
      }
      return item;
    }, {});
    const entity = Object.assign(user, filteredJson);
    if (entity.createTime) {
      entity.createTime = new Date(entity.createTime);
    }
    return entity;
  }

  toJson() {
    const proto = Object.getPrototypeOf(this);
    const ownProperties = Object.getOwnPropertyNames(this);
    const getters = Object.getOwnPropertyNames(proto).filter(key => {
      const descriptor = Object.getOwnPropertyDescriptor(proto, key);
      return descriptor && typeof descriptor.get === 'function';
    });
    const json = {}
    getters.forEach(key => {
      if (this.__proto__.hasOwnProperty(key)) {
        json[key] = this[key]
        this[key] = undefined
      }
    })
    ownProperties.forEach(key => {
      if (this.hasOwnProperty(key)) {
        json[key] = this[key]
        this[key] = undefined
      }
    })
    if (json.createTime && typeof json.createTime === 'object') {
      json.createTime = json.createTime.valueOf()
    } else {
      json.createTime = undefined
    }
    return JSON.parse(JSON.stringify(json))
  }
}

class UserEntity extends BaseEntity {
  nickname;
  age;
  gender;
  get sex() {
    if (this.gender === undefined || this.gender === null) {
      return undefined
    }
    return this.gender === '男' ? 1 : 0;
  }
  set sex(value) {
    if (value === undefined || value === null) {
      this.gender = undefined
    }else{
      this.gender = value === 1 ? '男' : '女';
    }
  }
}

const user = new UserEntity()
user.id = 1
user.nickname = "Hamm"
user.age = 18
user.gender = "男"
user.createTime = new Date()
console.log("entity", user)
console.log("json", user.toJson())

4. 继续调试输出,继续美滋滋

entity UserEntity {
  id: 1,
  createTime: 2024-10-23T19:37:07.521Z,
  nickname: 'Hamm',
  age: 18,
  gender: '男'
}
json { sex: 1, id: 1, createTime: 1729712227521, nickname: 'Hamm', age: 18 }

三、完整代码如下

class BaseEntity {
  id;
  createTime;

  static fromJson(json) {
    const user = new this();
    const filteredJson = Object.keys(json).reduce((item, key) => {
      if (user.hasOwnProperty(key)) {
        item[key] = json[key];
      }
      if (user.__proto__.hasOwnProperty(key)) {
        item[key] = json[key];
      }
      return item;
    }, {});
    const entity = Object.assign(user, filteredJson);
    if (entity.createTime) {
      entity.createTime = new Date(entity.createTime);
    }
    return entity;
  }

  toJson() {
    const proto = Object.getPrototypeOf(this);
    const ownProperties = Object.getOwnPropertyNames(this);
    const getters = Object.getOwnPropertyNames(proto).filter(key => {
      const descriptor = Object.getOwnPropertyDescriptor(proto, key);
      return descriptor && typeof descriptor.get === 'function';
    });
    const json = {}
    getters.forEach(key => {
      if (this.__proto__.hasOwnProperty(key)) {
        json[key] = this[key]
        this[key] = undefined
      }
    })
    ownProperties.forEach(key => {
      if (this.hasOwnProperty(key)) {
        json[key] = this[key]
        this[key] = undefined
      }
    })
    if (json.createTime && typeof json.createTime === 'object') {
      json.createTime = json.createTime.valueOf()
    } else {
      json.createTime = undefined
    }
    return JSON.parse(JSON.stringify(json))
  }
}

class UserEntity extends BaseEntity {
  nickname;
  age;
  gender;
  get sex() {
    if (this.gender === undefined || this.gender === null) {
      return undefined
    }
    return this.gender === '男' ? 1 : 0;
  }
  set sex(value) {
    if (value === undefined || value === null) {
      this.gender = undefined
    }else{
      this.gender = value === 1 ? '男' : '女';
    }
  }
}

const json = {
  id: 1,
  nickname: 'Hamm',
  age: 18,
  sex: 1,
  createTime: 1707021296000,
  bio: '一些废话,前端不需要的字段'
}
console.log("json",json)
const user = UserEntity.fromJson(json)
console.log("entity", user)
console.log("json", user.toJson())

四、总结

如上代码,我们利用了 getter/setter 以及 Object 原型链上的一些方法来完成了转换。

虽然稍显麻烦,但也算解决了不在外部写一些方法来转换。

各有所长,实现的方式有很多种,但思路才是很好玩的东西。

当然,JavaScript的装饰器提案已经快发布了,后续我们将继续摸索用装饰器在JavaScript中实现类似功能。(TypeScript的装饰器我们敢用,是因为编译后的JS代码没有包含装饰器的部分,在浏览器上不会有问题。)

到此这篇关于浅析如何使用JavaScript轻松实现数据转换的文章就介绍到这了,更多相关JavaScript数据转换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Boostrap中栅格布局的实现

    Boostrap中栅格布局的实现

    这篇文章主要为大家详细解析了Boostrap 栅格布局,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2017-01-01
  • JavaScript(js)处理的HTML事件、键盘事件、鼠标事件简单示例

    JavaScript(js)处理的HTML事件、键盘事件、鼠标事件简单示例

    这篇文章主要介绍了JavaScript(js)处理的HTML事件、键盘事件、鼠标事件,结合实例形式分析了JavaScript针对HTML事件、键盘事件及鼠标事件的简单处理方法,需要的朋友可以参考下
    2019-11-11
  • JS的拖拽属性draggable详解

    JS的拖拽属性draggable详解

    这篇文章主要介绍了JS的拖拽属性draggable详解,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • JavaScript 对象与数组操作大全

    JavaScript 对象与数组操作大全

    本文介绍了JavaScript中的对象和数组,包括它们的基本概念、创建方法、属性操作、遍历方法、增删改操作以及常用方法,同时,还讨论了原型和继承、对象的拷贝和方法简写等高级技巧,感兴趣的朋友跟随小编一起看看吧
    2026-02-02
  • js文件中引入另一个js文件的4种方法总结

    js文件中引入另一个js文件的4种方法总结

    JavaScript文件是一个文本类型的文件,在任何文本编辑器中都可以被打开和编辑,JavaScript文件的扩展名为js,这篇文章主要给大家介绍了关于js文件中引入另一个js文件的4种方法总结,需要的朋友可以参考下
    2023-12-12
  • JS中正则表达式全局匹配模式 /g用法详解

    JS中正则表达式全局匹配模式 /g用法详解

    本文章通过实例代码给大家详细介绍js中正则表达式的全局匹配模式 /g的用法,需要的朋友参考下
    2017-04-04
  • js多级树形弹出一个小窗口层(非常好用)实例代码

    js多级树形弹出一个小窗口层(非常好用)实例代码

    js多级树形弹出一个小窗口层(非常好用)实例代码,需要的朋友可以参考一下
    2013-03-03
  • JavaScript手写实现一个简单的快捷键库

    JavaScript手写实现一个简单的快捷键库

    前端开发中,有时项目会遇到一些快捷键需求,比如绑定快捷键,展示快捷键,编辑快捷键等需求,所以本文就来用JavaScript手写一个简单的快捷键库吧
    2024-02-02
  • layui 实现表单和文件上传一起传到后台的例子

    layui 实现表单和文件上传一起传到后台的例子

    今天小编就为大家分享一篇layui 实现表单和文件上传一起传到后台的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • JS实现字符串中去除指定子字符串方法分析

    JS实现字符串中去除指定子字符串方法分析

    这篇文章主要介绍了JS实现字符串中去除指定子字符串方法,结合实例形式分析了javascript使用字符串替换与分割、聚合两种子字符串去除相关操作技巧,需要的朋友可以参考下
    2018-05-05

最新评论