源码共读,第36期 | omit.js 剔除对象中的属性

2,133 阅读4分钟

前言

本文参加了由公众号@若川视野 发起的每周源码共读活动点击了解详情一起参与。

本篇是源码共读第36期 | 可能是历史上最简单的一期 omit.js 剔除对象中的属性,点击了解本期详情

准备

首先omit.js是什么?有什么作用?

虽然大家可能都知道但是我还是简单粗暴用谷歌翻译下官方说明啊,那就是用于创建已删除某些字段的对象的浅表副本的实用函数。 具体是什么样子呢,官方有给举例

var omit = require('omit.js');
omit({ name: 'Benjy', age: 18 }, [ 'name' ]); // => { age: 18 }

另外,那个......本人真真一个英语白痴,omit单词都还不大会读,也是火速去谷歌查一下,omit有省略、忽略等意思😂ok,简单了解了下,现在就开始呗

  1. 拉取代码
git clone https://github.com/benjycui/omit.js.git
  1. 安装依赖
npm i
  1. 执行测试用例
npm run test

结果如下:

omit-test.png

(实不相瞒,我一开始纠结于执行😂因为已经习惯直接run serve/dev/start 跑起来看效果了,一拿到有点不知从哪开始也没看后面对应的语句,下意识执行了run start结果路径个人马虎选错了一直没效果我就更不知怎么下手了,下面会解释这些命令对应什么)

目录

omit-ml.png

package.json

{
  "name": "omit.js", // 包名
  "version": "2.0.2", // 迭代版本
  "description": "Utility function to create a shallow copy of an object which had dropped some fields.", // 描述
  "main": "lib/index.js", // 入口文件
  "module": "es/index.js", // ESM规范声明入口文件
  "types": "index.d.ts", // TS类型声明入口文件
  "files": [ // 被项目包含的文件名数组
    "lib",
    "es",
    "dist",
    "index.d.ts"
  ],
  "scripts": {
    "start": "father doc dev --storybook", // 运行项目并生成文档视图
    "build": "father doc build --storybook", // 构建项目并生成文档视图
    "compile": "father build", // 构建项目
    "gh-pages": "father doc deploy", // 发布文档
    "prepublishOnly": "npm run compile && np --yolo --no-publish", // 编译并发布包
    "lint": "eslint .", 
    "test": "father test", // 运行测试用例
    "coverage": "father test --coverage" // 测试覆盖率
  },
  "repository": { // git地址
    "type": "git",
    "url": "git+https://github.com/benjycui/omit.js.git"
  },
  "keywords": [ // 搜索关键字
    "object",
    "omit"
  ],
  "author": "Benjy Cui<benjytrys@gmail.com>", // 作者
  "license": "MIT", // 许可证
  "bugs": {
    "url": "https://github.com/benjycui/omit.js/issues" // bug提交地址
  },
  "homepage": "https://github.com/benjycui/omit.js#readme", // 项目包官网地址
  "devDependencies": { // 开发环境所需以来
    "@umijs/fabric": "^2.2.2",
    "assert": "^1.4.1",
    "eslint": "^7.4.0",
    "father": "^2.29.5",
    "np": "^6.3.1",
    "rc-tools": "^6.3.3"
  }
}

阅读的时候发现了一个自己从来没见过的东西father,而且每一个脚本相关运行还都与其相关,就抓紧去查阅了下

father

father 是umijs下基于rollup、docz、storybook、jest、prettier和eslint的打包和文档工具,npm指路 / git地址。如果感兴趣可以自己去官方详细阅读下,在此简单说下用到的这几个

"start": "father doc dev --storybook",
"build": "father doc build --storybook",
"gh-pages": "father doc deploy",

这三个脚本是docz配置,doc dev将在开发环境下,展示项目中的.md文档,本库中是README.md文件, 启动后可看到

图片说明

doc build模式将会本地构建.doc目录,可以将其目录下文件上传到服务器。 doc deploy模式将会自动部署到gitHub目录。

"compile": "father build"

build打包库,输出多种格式文件

"prepublishOnly": "npm run compile && np --yolo --no-publish"

我个人理解就是构建后使用np去帮助我们快速发布npm包

单元测试

import assert from 'assert';
import omit from '../src';

describe('omit', () => {
  it('should create a shallow copy', () => {
    const benjy = { name: 'Benjy' };
    const copy = omit(benjy, []);
    assert.deepEqual(copy, benjy);
    assert.notEqual(copy, benjy);
  });

  it('should drop fields which are passed in', () => {
    const benjy = { name: 'Benjy', age: 18 };
    assert.deepEqual(omit(benjy, ['age']), { name: 'Benjy' });
    assert.deepEqual(omit(benjy, ['name', 'age']), {});
  });
});
```assert```是个断言测试依赖包,此处使用了其两个方法```assert.deepEqual``````assert.notEqual```

前者是遍历对象所有自身的且可枚举的属性,进行比较相等。后者是比较不相等,只有在实际值等于预期值时,会抛出错误。什么可枚举比较是怎样呢,例如:

let obj = { a: 1};
let obj1 = Object.create(obj);
console.log(Object.keys(obj)); // ['a']
console.log(Object.keys(obj1)); // []
assert.deepEqual(obj, obj1);
// AssertionError: { a: 1 } deepEqual {} 此时就不相等
let obj2 = obj
console.log(Object.keys(obj2)); // ['a']
assert.deepEqual(obj, obj2);
// OK

源码

function omit(obj, fields) {
  // eslint-disable-next-line prefer-object-spread
  const shallowCopy = Object.assign({}, obj);
  for (let i = 0; i < fields.length; i += 1) {
    const key = fields[i];
    delete shallowCopy[key];
  }
  return shallowCopy;
}

export default omit;
  1. 函数内部创建一个局部变量shallowCopy 通过Object.assign将obj所有可枚举属性复制到shallowCopy
  2. fields传入的是一个对象属性名数组,将其循环遍历拿到各属性key,将存在于shallowCopy对象上的相对应的key进行移除
  3. 返回shallowCopy

注:这里没加判断,我觉得加了判断会更完善一些

总结

  1. 学习了omit的源码实现
  2. 复习了Object.assign Object.create
  3. 了解father
  4. 了解测试用例的使用

同时也发现了个人的一些不足之处

  1. 对打包发布等了解甚少,自己之前只关注开发阶段,校验、单测、文档站、打包发布等还没着手,自己目前还没有发布过自己的npm包,下次可以尝试下
  2. 不熟悉测试用例,没有写过,平时都是打断点