源码共读第一天,工具函数--omit.js
本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。 这是源码共读的第36期,链接:juejin.cn/post/711878…
Omit 简介
非常简单的一个库,一句话即可概括:
Utility function to create a shallow copy of an object which had dropped some fields.
直译过来:一个实用的工具函数,用于创建某些被删除了字段的对象的浅拷贝
源码解析
定义一个工具函数,入参有两个
obj:为需要删除属性的原对象
fields:数组形式,元素为被删除的字段
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()方法,如果针对的是一级对象,进行的是深拷贝。 但是如果是多级对象,多级对象本身其实是个浅拷贝,这里称呼为shallowCopy是否恰当?此外是否应该对多级对象进行递归的深拷贝?恳请大佬解答~
let test = {name:"xiaowang",age:18,sex:"female",family:{father:"lisi",brother:"liwu"}}
let res = omit(test,[])
console.log(test) //{
name: 'xiaowang',
age: 18,
sex: 'female',
family: { father: 'lisi', brother: 'liwu' }
}
console.log(res) // {
name: 'xiaowang',
age: 18,
sex: 'female',
family: { father: 'lisi', brother: 'liwu' }
}
console.log(res===test) //false
res.family.father = "wangliu"
console.log(test) //{
name: 'xiaowang',
age: 18,
sex: 'female',
family: { father: 'wangliu', brother: 'liwu' }
}
console.log(res) // {
name: 'laowang',
age: 18,
sex: 'female',
family: { father: 'wangliu', brother: 'liwu' }
}
console.log(res===test) //false
单元测试
一个良好的工具函数需要单测保证质量,omit.js使用的是node的内置断言库assert,有strict和legacy两种模式,建议只使用strict模式。
import assert from 'assert';
import omit from '../src/index.js';
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.strictEqual(actual, expected[, message]) strictEqual是严格等于,除了比较值或者对值得引用外,还要比较类型。
// The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
// 这个是严格相等, ===, 如果不严格相等,抛出异常
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, '===', assert.strictEqual);
}
};
- assert.notEqual(actual, expected[, message]) 直接测试两个值不相等
// The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
// 直接测试不相等,如果相等 == ,抛出异常
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, '!=', assert.notEqual);
}
};
- fail函数
// 对AssertionError的进一步封装, 直接抛出AssertionError异常,
// 注意: 如果有异常消息,直接显示异常消息,如果没有,直接显示实际值,期望值和操作符组成的字符串,具体实现在getMessage
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
总结
-
omit.js作为一个开源库,不能仅限于核心代码,测试、打包发布等都要注意,对于项目工程化也有一定的借鉴意义
-
对单元测试有了进一步的了解,同时学习assert的部分源码,可以借鉴其封装思路