本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。这是源码共读的第36期 。
我们会遇到使用一个对象但却不需要对象的某一个属性的场景。作为一个有js开发使用经验的人,问我们怎么删除对象属性的时候我们都会想到delete。但delete之后,对象中就没有这个属性了。所以解决方案就是:拷贝这个对象所有用到的属性,但是不要那个(或哪些)用不到的属性。这样一句话对应到代码中就是好多行,如果有个写好的工具方法让我们用岂不是很快乐嘛~ omit.js 就干这个事!我们一起学习其使用和源码吧~
1.准备工作
- clone代码
https://github.com/benjycui/omit.js
- 了解omit是啥?
是实用的工具函数用于创建已删除某些字段的对象的浅副本。
var omit = require('omit.js');
omit({ name: 'Benjy', age: 18 }, [ 'name' ]); // => { age: 18 }
- 号外:omit此单词第一次碰到,真不知道啥意思,含义见下图:
可以看这篇文章abolish,cancel,delete与omit有什么共同点你能进行顺序排列吗,了解更多词汇方面的解释。下面看一下omit的源码:
2.源码解读
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;
首先使用Object.assign对源对象obj进行浅拷贝。(Note: 这块默认你就会传对象,没有进行参数检查。缺少try...catch或相应异常处理逻辑)
遍历fields数组,取对象属性逐一删除。(Note: 感觉这块强制files是数组不太好,有时候我们使用的时候就想删除一个属性,最好支持一下字符串,如果是字符串就将此字符串当作属性删除。)
下面验证一下Object.assign为浅拷贝,见下图:
如上图所示,使用Object.assign将obj的属性复制给obj2, 其中obj的属性c是数组,属于引用类型的数据。当修改obj时,我们发现obj2的c属性也发生变化了。所以Object.assign()方法是一个对象的浅拷贝方法。omit的源码可以说非常简单,但是package.json中的一些npm包还是挺有学习价值的,我们来简单了解一下:
3.npm包积累
- father: Library toolkit based on rollup, docz, storybook, jest, prettier and eslint。
在omit.js的package.json文件中的好几个 npm script都有用到father,例如:
"start": "father doc dev --storybook",
"build": "father doc build --storybook",
"compile": "father build",
"gh-pages": "father doc deploy",
能够看到father又能打包编译又能生成文档,下图是执行run start命令的执行结果:
- storybook: Storybook is an open source tool for building UI components and pages in isolation. It streamlines UI development, testing, and documentation。(引自:storybook.js.org/)
我们执行run start之所以能够把readme.md显示在浏览器中就又storybook的功劳。
- assert: The assert module from Node.js, for the browser. 所以使用方法还是要看nodejs.org/api/assert.…
在omit.js的tests/index.test.js中使用assert进行测试用例的书写:
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']), {});
});
});
- umi-fabric:一个包含 prettier,eslint,stylelint 的配置文件合集
omit.js的.eslintrc.js文件内容如下:
const base = require('@umijs/fabric/dist/eslint');
module.exports = {
...base,
rules: {
...base.rules,
'no-template-curly-in-string': 0,
'prefer-promise-reject-errors': 0,
'react/no-array-index-key': 0,
'react/sort-comp': 0,
'import/no-named-as-default': 0,
'import/no-named-as-default-member': 0,
},
};
可见umijs/fabric提供了一些规则,使用时可以补充自己的规则或者覆盖一些规则。
- np: A better npm publish
帮助进行nmp包发布,在omit.js中是这样使用的:
"prepublishOnly": "npm run compile && np --yolo --no-publish",
先执行compile(其实就是father-build),然后使用 np, 下图是运行的结果:
毫无疑问地以失败告终,有git 的 push tags权限。
- rc-tools: offline tools for react component
没看到在哪块有用到。
至此,omit.js算是学完了,怎么能用到我们的项目中呢?看下面的内容:
4.学习致用
想到我在代码里常常会写delete, 例如下面的代码:
try {
const param = JSON.parse(JSON.stringify(this.form))
delete param.lonLat
await createCarStore({
...param,
});
this.$message.success('提交成功!');
this.$router.go(-1);
} catch (error) {
this.$message.error(error.data.remark);
}
使用omit.js 就可以写成这样:
try {
const param = omit(this.form, ['lonLat'])
await createCarStore({
...param,
});
this.$message.success('提交成功!');
this.$router.go(-1);
} catch (error) {
this.$message.error(error.data.remark);
}
两行变一行,何乐而不为?
5.总结
学完本期源码,笔者有如下收获:
- 复习了Object.assgin方法,加深对深浅拷贝的理解
- 了解到father, storybook等npm包的使用
- 学习了如何发布npm包
- 可以使用omit.js来优化项目代码
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。