前言
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
本篇是源码共读第36期 | 可能是历史上最简单的一期 omit.js 剔除对象中的属性,点击了解本期详情
准备
首先omit.js是什么?有什么作用?
虽然大家可能都知道但是我还是简单粗暴用谷歌翻译下官方说明啊,那就是用于创建已删除某些字段的对象的浅表副本的实用函数。 具体是什么样子呢,官方有给举例
var omit = require('omit.js');
omit({ name: 'Benjy', age: 18 }, [ 'name' ]); // => { age: 18 }
另外,那个......本人真真一个英语白痴,omit单词都还不大会读,也是火速去谷歌查一下,omit有省略、忽略等意思😂ok,简单了解了下,现在就开始呗
- 拉取代码
git clone https://github.com/benjycui/omit.js.git
- 安装依赖
npm i
- 执行测试用例
npm run test
结果如下:
(实不相瞒,我一开始纠结于执行😂因为已经习惯直接run serve/dev/start 跑起来看效果了,一拿到有点不知从哪开始也没看后面对应的语句,下意识执行了run start结果路径个人马虎选错了一直没效果我就更不知怎么下手了,下面会解释这些命令对应什么)
目录
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;
- 函数内部创建一个局部变量shallowCopy 通过Object.assign将obj所有可枚举属性复制到shallowCopy
- fields传入的是一个对象属性名数组,将其循环遍历拿到各属性key,将存在于shallowCopy对象上的相对应的key进行移除
- 返回shallowCopy
注:这里没加判断,我觉得加了判断会更完善一些
总结
- 学习了omit的源码实现
- 复习了
Object.assign和Object.create - 了解
father - 了解测试用例的使用
同时也发现了个人的一些不足之处
- 对打包发布等了解甚少,自己之前只关注开发阶段,校验、单测、文档站、打包发布等还没着手,自己目前还没有发布过自己的npm包,下次可以尝试下
- 不熟悉测试用例,没有写过,平时都是打断点