easy-copy,让对象间复制变得简单

作品2016-09-170 篇评论 JavaScript NPM 模块

在 JavaScript 的开发中,经常会遇到在对象间进行属性复制的情况,比如说下面这个在服务器中对表单进行过滤的例子。

function createUserInfo(req, res, next) {
  const body = req.body;
  const data = {
    name: body.name,
    age: body.age,
    major: body.major,
    email: body.email
  }
  User.save(new User(data)).then(user => {
    res.send('创建用户成功');
  }
}

为了确保用户表单的数据不会对其它字段造成意料之外的影响,比如说恶意修改权限之外的字段之类的情况,一般都会需要对表单进行过滤操作。如果只是少数属性需要这样过滤的话还好,如果有十几个甚至几十个属性需要过滤的话,那么多重复的代码也会把人搞迷糊。那么,有什么好的方法能够减轻这样的负担呢?

ease-copy 介绍

ease-copy 是我自己开发的一个 NPM 工具模块,可同时用在 Node 及浏览器环境下。正因为有了类似于上面这样的需求,我忍不住自己动手开发了这样的一个工具。

语法

easycopy(src [, filter [, opt]])
  • src: 属性的源对象,所有的属性都从其中而来
  • filter: 过滤条件,可以为字符串、数组、对象,可深层嵌套
  • opt:复制选项(下面会介绍)

安装

NPM 安装:适用于 Node 环境下

$ npm install easy-copy --save

Bower 安装:适用于浏览器环境下

$ bower install easy-copy --save

使用 easy-copy

既然安装好了,那就赶紧尝试一下吧。easy-copy 的适用环境有很多,包含了从最初级到高级的用法,下面就让我们来一步步地看看。

初级用法 - 简单数据过滤

用上了 easy-copy 这个工具模块的话,文章开始的那一段代码只需要像如下操作即可:

const easycopy = requrie('easy-copy');

function createUserInfo(req, res, next) {
  const body = req.body;
  const data = easycopy(body, ['name', 'age', 'major', 'email']);
  User.save(new User(data)).then(user => {
    res.send('创建用户成功');
  })
}

注:运行在浏览器中的 easy-copy ,会在 script 标签执行时自动添加上 easycopy 这个全局对象,即不需要使用 require 语句,其它的与 node 下完全相同。

怎么样,是不是感觉简洁、方便了许多?然而这只是初级用法,让我们继续看下去。

中级用法 - 数据非空验证

平常对表单输入的验证一般如下:

function valid() {
  if (!form.username || !form.password || !form.repassword || !form.age || !form.major) {
    return false
  } else {
    return true;
  }
}

看到这样一段冗长又重复的代码,一般都会感到心累,要是表单的字段再多些会怎样?不过如果用上 easy-copy 之后,就变得简单了:

function valid() {
  var data = easycopy(form, ['username', 'password', 'repassword', 'age', 'major']);
  for (var prop in data) {
      if (!data[prop]) {
          return false;
      }
  }
  return true;
}

凡是在 filter 中存在的属性,只要在源对象中不存在,就默认赋值为 undefined,让数据验证变得更简单。

高级用法 - 深拷贝过滤

easy-copy 除了可以做简单的浅复制,也可完全实现深拷贝,这对于复制一个嵌套对象类型的属性是非常有用的。

const foo = {
  id: 1,
  children: [
    { id: 2, children: [] },
    {
      id: 3,
      children: [
        { id: 4, children: [] },
        { id: 5, children: [] }
      ]
    },
    { id: 6, children: [] }
  ]
}

对于上面这个对象和数组相结合的混合嵌套对象,easy-copy 依然可以轻松搞定。就比如说我只需要保留它 children 属性的第二个对象属性,用如下代码即可实现:

const bar = easycopy(foo, {children: 1})

console.log(bar);
// {
//   children: [
//     {
//       id: 3,
//       children: [
//         { id: 4: children: [] },
//         { id: 5: children: [] }
//       ]
//     }
//   ]
// }

但如果我只想保留 id 为 4 及 id 为 6 的那两个对象属性呢?同样 So easy!

const baz = easycopy(foo, {children: [{1: {children: 0}}, 2]});

console.log(baz);
// {
//   children: [
//     {
//       children: [
//         { id: 4, children: [] }
//       ]
//     },
//     { id: 6, children: [] }
//   ]
// }

可选选项

easycopy 的第三个参数是 opt,支持过滤选项。目前的 v1.0 版本只支持一个选项,就是是否自动将源对象不存在的属性的值在目标对象中设置为 undefined。默认值是 true,也就是说主要依靠 filter 来设置过滤后的对象属性值。

const foo = {
  a: 1,
  b: 2,
  c: {
    d: 1,
    e: 2
  }
}

const bar = easycopy(foo, [{c: ['d', 'z']}, {f: 'h'}]);
// {
//   c: {
//     d: 1,
//     z: undefined
//   },
//   f: {
//     h: unfined
//   }
// }

const baz = easycopy(foo, [{c: ['d', 'z']}, {f: 'h'}], {undefined: false});
// {
//   c: {
//     d: 1,
//   },
// }

也就是说你能够随心所欲地按照自己的需求来过滤和拷贝数据了,不会再遇到类似于 Cannot read property 'xxx' of undefined 这样令人讨厌的错误提示了。

总结

easy-copy 是一个功能很强大的工具库,可以用最简短的代码完成数据浅拷贝、深拷贝以及深层次的数据对象及数组过滤等功能。本项目的仓库为 https://github.com/DremyGit/easy-copy ,如果觉得好用欢迎 Star,也可以在评论区下方讨论。

评论区

发表评论
用户名
(必填)
电子邮箱
(必填)
个人网站
(选填)
评论内容
Copyright © 2017 dremy.cn
皖ICP备16015002号