omit.js 源码浅析
- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第36期,链接:juejin.cn/post/711878…
源码地址:omit.js
什么是omit
看到这个名字的我就想到ts中的Omit,再一看omit.js的描述: 创建删除某些字段的对象的浅拷贝副本;
ts中的Omit同样是去掉已声明类型中的某些属性;
打开项目的index.d.ts文件一看,果然也是如此;
declare function Omit<T, K extends keyof T>(
obj: T,
keys: Array<K>
): Omit<T, K>;
export default Omit;
- 使用示例
omit.js
var omit = require('omit.js');
omit({ name: 'Benjy', age: 18 }, [ 'name' ]); // => { age: 18 }
typescript内的Omit
type IPerson = {
name: string,
age: number,
test: string
}
type testType = Omit<IPerson, 'name' | 'age'>
const person: IPerson = {
name: '张三',
age: 18,
test: '遵纪守法是对人的最低道德要求'
}
const errorEg: testType = {
test: '遵纪守法是对人的最低道德要求',
// age在此处会报错ts错误
// Type '{ test: string; age: number; }' is not assignable to type 'testType'. Object literal may only specify known properties, and 'age' does not exist in type 'testType'.(2322)
age: 18,
}
项目配置
打开本项目的package.json文件看看都引入了什么好东西
{
// ...
"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"
},
// ...
"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"
}
}
-
@umijs/fabric: 集成各种lint工具
- 使用官方示例
// 也算方便了使用方,不用各种重新配置,可以借鉴下用在公司里面 module.exports = { extends: [require.resolve('@umijs/fabric/dist/eslint')], // in antd-design-pro globals: { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, page: true, }, rules: { // your rules }, }; -
father:集合各种打包姿势的库,看着还集合了测试框架(名字起的很有特点)
-
np:A better
npm publish,这东西不错 -
rc-tools:应该也是打包相关的,看
commit貌似被father换掉了
核心代码
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;
}
主要使用Object.assign返回一个拷贝的对象,并循环fields对象并把obj对应的keydelete 删掉,因为delete对象属性时无论成功与否都不会报错,只会返回true OR false(当对象被freeze后是无法删除成功的)
复习下Object.assign:
Object.assign() 方法将所有可枚举(Object.propertyIsEnumerable() 返回 true)的自有(Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象(eg: Object.assign({}, obj1, obj2)),返回修改后的对象。假如源对象是一个对象的引用,它仅仅会复制其引用值。
测试用例
assert这个库平时用的比较少,查了资料瞄了下
describe('omit', () => {
it('should create a shallow copy', () => {
const benjy = { name: 'Benjy' };
const copy = omit(benjy, []);
// 1
assert.deepEqual(copy, benjy);
// 2
assert.notEqual(copy, benjy);
});
it('should drop fields which are passed in', () => {
const benjy = { name: 'Benjy', age: 18 };
// 3
assert.deepEqual(omit(benjy, ['age']), { name: 'Benjy' });
// 4
assert.deepEqual(omit(benjy, ['name', 'age']), {});
});
});
deepEqual: 深入对比两个对象自身可枚举的属性值,只要key:value匹配即可
notEqual: 浅层比较对象,类似 ==
-
用例1 ;
assert.deepEqual(copy, benjy) // => name: 'Benjy' == name: 'Benjy' -
用例2:
copy和benjy是两个对象,引用不同确实notEqual -
用例3:
assert.deepEqual(omit(benjy, ['age']), { name: 'Benjy' }); // omit(benjy, ['age']) => { name: 'Benjy' } // name: 'Benjy' == name: 'Benjy' -
用例4: 其实就是
{}与{}的deepEqual
实现一个简易的deepOmit方法
按照omit.js的逻辑 简单实现一个深度删除某些字段的deepOmit.js
const deepOmit = (data: any, keys: string[]) => {
const newData: any = JSON.parse(JSON.stringify(data)) || {}
const deepOmitFn = (obj: any) => {
for(let key of keys) {
delete obj[key]
}
Object.values(obj).forEach((value) => {
if (value && typeof value === 'object') {
deepOmitFn(value)
}
})
}
deepOmitFn(newData)
return newData
}
// test
console.log(deepOmit({name: '222', age: 2, a: 'a', b: {name: 'b-name', age: 22}}, ['name'])) => // {age: 2, a: 'a', b: {age:22}}
unset-value
后续根据omit.js找到unset-value,实现功能更加高级了点,同样也能实现deep-omit功能,只是它只会在原对象上操作而不会返回一个新的对象,具体看示例
var unset = require('unset-value');
var obj = {a: 'b'};
unset(obj, 'a');
console.log(obj);
//=> {}
// delete nested values
var one = {a: {b: {c: 'd'}}};
unset(one, 'a.b');
console.log(one);
//=> {a: {}}
var two = {a: {b: {c: 'd'}}};
unset(two, ['a', 'b', 'c']);
console.log(two);
//=> {a: {b: {}}}
var three = {a: {b: {c: 'd', e: 'f'}}};
unset(three, 'a.b.c');
console.log(three);
//=> {a: {b: {e: 'f'}}}
具体请看github地址
总结
- 对
Object.assign的复习 - 了解了
assert的一般使用和某些方法的实现 - 了解了
father等库 - 根据omit找到了另一个类似库
unset-value