- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第36期,链接:【若川视野 x 源码共读】第36期 | 可能是历史上最简单的一期 omit.js 剔除对象中的属性。
0 环境
- 编辑器:webstorm或者vscode
- 系统版本:windows10
- 编辑器版本:最新
- 浏览器:谷歌
- node等:最新
1 准备
2 前言
我们拉取omit.js源码,然后yarn install,运行即可
3 看文档
先看源码下面的文档,根据它给的API和案例,可以得出个结论,omit 它需要接收两个参数,第一个参数是目标对象(Object类型),第二个参数是数组并且是字符串类型(存在要移除的key),返回值是一个Object。根据第二个参数里的key,剔除掉目标对象里对应的key以及它的value。
4 核心源码
找到src的目录下的index.js文件。参考上面的解释,omit包含两个参数,将obj浅拷贝了一份(shallowCopy),循环fields,挨个得到key,然后shallowCopy拿到key,删除。
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;
现在的疑点,为啥需要浅拷贝,我直接操作对象不可以? 首先浅拷贝的定义:我自己创建一个新的对象,接收要重新copy或引用的对象值,假如是基本的数据类型,直接复制值给新对象就好了,若是引用数据类型,复制的就是内存中的地址,你的一个改变会影响到目标对象。根据我的调试,我认为这里浅拷贝的意义在于:我多次调用omit(希望这里的目标对象不受影响),正好针对基本的数据类型,删除操作的话,不会影响到目标对象,就很实用了。
要是遇到嵌套多的那种对象,对我来说,不涉及到函数、undefined、symbol、日期、不可枚举这些,丐版JSON.stringify应该就够了。
还有比如目标对象为空或者fields为空时的处理。
function omit(obj, fields) {
// eslint-disable-next-line prefer-object-spread
if (Object.keys(obj).length === 0 || fields.length === 0) {
return Object.assign({}, obj)
}
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;
5 测试omit
首先找到test的文件,如下图:
断言结果: 若不满足条件,就会抛出错误。assert.deepEqual():深度比较下的相等:基本类型值比较,引用类型也是比较它们的属性的值比较。assert.notEqual():浅比较不相等,判断基本类型或引用类型(对比地址)不相等,则满足期望。
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 };
const copy = omit(benjy, ['age'])
const copy1 = omit(benjy, ['name', 'age'])
const copy2 = omit(benjy, ['name', 'age1'])
assert.deepEqual(omit(benjy, ['age']), { name: 'Benjy' });
assert.deepEqual(omit(benjy, ['name', 'age']), {});
});
});
如下图:解释了上面浅拷贝的好处:这里虽然多次使用omit,但是benjy没有改变,copy和copy1变量都得到了想要的值,而copy2里age1这个key,benjy里没有,抛出了异常。