浅析如何使用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数据转换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • js实现全选和全不选

    js实现全选和全不选

    这篇文章主要为大家详细介绍了js实现全选和全不选,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • 利用纯JS实现像素逐渐显示的方法示例

    利用纯JS实现像素逐渐显示的方法示例

    这篇文章主要给大家介绍了利用纯JS实现像素逐渐显示的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-08-08
  • JavaScript tab选项卡插件实例代码

    JavaScript tab选项卡插件实例代码

    这篇文章主要介绍了JavaScript tab选项卡插件实例代码的相关资料,需要的朋友可以参考下
    2016-02-02
  • Echarts图例组件的属性与源代码

    Echarts图例组件的属性与源代码

    图例组件展现了不同系列的标记(symbol),颜色和名字,可以通过点击图例控制哪些系列不显示,这篇文章主要给大家介绍了关于Echarts图例组件的相关资料,需要的朋友可以参考下
    2021-06-06
  • IE6浏览器中window.location.href无效的解决方法

    IE6浏览器中window.location.href无效的解决方法

    这篇文章主要介绍了IE6浏览器中window.location.href无效的解决方法,给出了正确与错误的实例对比,分析跳转无效的原因与解决方法,是非常实用的技巧,需要的朋友可以参考下
    2014-11-11
  • JavaScript利用canvas实现鼠标跟随特效

    JavaScript利用canvas实现鼠标跟随特效

    canvas是一个很神奇的玩意儿,比如画表格、画海报图都要用canvas去做。本文就来利用canvas制作个简单的鼠标跟随特效,快跟随小编一起学习一下吧
    2022-10-10
  • JavaScript中三种for循环语句的使用总结(for、for...in、for...of)

    JavaScript中三种for循环语句的使用总结(for、for...in、for...of)

    这篇文章主要给大家介绍了关于JavaScript中三种for循环语句的使用的相关资料,For循环用在需要重复执行的某些代码,本文介绍的三种for循环分别包括for、for...in、for...of,需要的朋友可以参考下
    2021-06-06
  • JS实现面包屑导航功能从零开始示例

    JS实现面包屑导航功能从零开始示例

    这篇文章主要为大家介绍了JS实现面包屑导航功能从零开始示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • reveal.js PPT制作框架使用教程

    reveal.js PPT制作框架使用教程

    reveal.js是一款开源的HTML演示框架,由Hakim El Hattab开发,遵循MIT许可证,它支持嵌套幻灯片、Markdown、自动动画、PDF导出等多种功能,本文就来介绍一下如何使用,感兴趣的可以了解一下
    2024-09-09
  • 使用JavaScript将图片合并为PDF的实现

    使用JavaScript将图片合并为PDF的实现

    在日常工作中,我们可能需要拍摄一些照片并将图像合并到PDF文件中,这可以通过许多应用来完成,Dynamsoft Document Viewer让这一操作更加方便,在本文中,我们将使用Dynamsoft Document Viewer创建一个Web应用,用JavaScript将图像合并到PDF中,需要的朋友可以参考下
    2024-07-07

最新评论