本文参加了由公众号@若川视野发起的每周源码共读活动,点击了解详情一起参与。 这是源码共读的第 36 期,链接:juejin.cn/post/711878…
前言
这是我参加源码共读活动的第 3 次笔记。
学习任务
- 主要学会通过测试用例调试源码。
- 可以多关注怎么发布 npm 包的、commonjs、esm、测试用例 、ts 等(也可以不关注)。
- 加油。
环境准备
- 拉取项目
- 安装依赖
- 调试、理解代码
- 快速调试、理解代码访问:访问 github1s 快速调试
- 在某些项目中,通过.github/contributing.md ,来了解目录结构
开始
一、omit.js 文档:如何使用?
- 安装
- 工具函数创建一个被删除属性的对象的浅副本。
npm i --save omit.js
- 用法
var omit = require("omit.js");
omit({ name: "Benjy", age: 18 }, ["name"]); // => { age:18 }
- API
omit(obj: Object, fields: string[]): Object
- 返回已删除字段的浅副本
二、omit.js 运行测试用例
// clone project
npm i
npm run test
三、omit.js 源码
-
源代码
src/index.js
/** * 返回已删除字段的浅副本 * 不懂什么意思看注释 */ function omit(obj, fields) { // eslint-disable-next-line prefer-object-spread const shallowCopy = Object.assign({}, obj); // 把 obj 浅拷贝成 shallowCopy for (let i = 0; i < fields.length; i += 1) { // i 加 1 后赋值给自己 const key = fields[i]; delete shallowCopy[key]; } // 依次删掉 obj 的浅拷贝 shallowCopy 的属性(根据属性列表 fields) return shallowCopy; // 并返回 } export default omit;- Object.assign
- what
- 所有可枚举(?) 的 自有(?) 属性,
- 所有可枚举(?):Object.propertyIsEnumerable() 返回 true
- 自有(?):Object.hasOwnProperty() 返回 true
- 一/多个 源对象 复制到 目标对象,
- 返回修改后的对象。
- 所有可枚举(?) 的 自有(?) 属性,
- 示例
const target = { a: 1, b: 2 }; const source = { b: 4, c: 5 }; const returnedTarget = Object.assign(target, source); console.log(target); // Expected output: Object { a: 1, b: 4, c: 5 } console.log(returnedTarget === target); // Expected output: true- 右边的 source 扔进左边的 target 里,相同属性的值用 source 里的,从而得到新的 target ;target 和
Object.assign()方法返回值 returnedTarget 相等。
- 右边的 source 扔进左边的 target 里,相同属性的值用 source 里的,从而得到新的 target ;target 和
- 语法
const returnedTarget = Object.assign(target, ...sources);- target :目标对象,接收源对象属性的对象,也是修改后的返回值。
- sources :源对象,包含将被合并的属性。
- returnedTarget :返回值,目标对象。
- target 与 sources 有同 key,则 target 属性将被 sources 属性覆盖,后面 sources 属性,类似覆盖,前面 sources 属性。
- Object.assign 方法只会拷贝源对象 可枚举的 和 自身的 属性到目标对象。
- 为了将属性定义(包括其可枚举性)复制到原型,应使用 Object.getOwnPropertyDescriptor() 和 Object.defineProperty(),基本类型 String 和 Symbol 的属性会被复制。
- 尽力而为、可能只会完成部分复制的方法。赋值期间出错,属性不可写,则会抛出 TypeError,抛出异常前添加任何属性,会修改 target 对象。
- 备注:Object.assign() 不会在 source 对象值为 null 或 undefined 时抛出错误。
- 深拷贝问题:Object.assign() 只复制属性值,so 针对深拷贝, 需要使用其他办法。
- 参考链接 更多见 mdn - Object.assign()
- what
- Object.assign
-
测试用例
tests/index.test.js
import assert from "assert"; // 工具函数 断言。 import omit from "../src"; // 返回删掉原对象 obj 某些属性的后的浅拷贝副本 shallowCopy 。 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"]), {}); }); });- 解释:
// - 测试 omit 的用例(describe): // 1. 应该创建一个浅拷贝(first it): // - benjy = { name: "Benjy" } // - benjy 不删属性,其浅拷贝为 copy // - 断言:copy 和 benjy 深度相等 // - 断言:copy !== benjy // 2. 应该删掉通过的属性(second it): // - benjy = { name: "Benjy", age: 18 } // - 断言:benjy 的浅拷贝小红,小红删掉 age 属性后,小红和 { name: "Benjy" } 深度相等。 // - 断言:benjy 的浅拷贝小绿,小绿删掉 name & age 属性后,小绿和 {} 深度相等。
四、assert 断言依赖里的几个工具函数
node_modules/assert/assert.js
-
fail
// At present only the three keys mentioned above are used and // understood by the spec. Implementations or sub modules can pass // other keys to the AssertionError's constructor - they will be // ignored. // 3. All of the following functions must throw an AssertionError // when a corresponding condition is not met, with a message that // may be undefined if not provided. All assertion methods provide // both the actual and expected values to the assertion error for // display purposes. function fail(actual, expected, message, operator, stackStartFunction) { throw new assert.AssertionError({ message: message, actual: actual, expected: expected, operator: operator, stackStartFunction: stackStartFunction, }); } // EXTENSION! allows for well behaved errors defined elsewhere. assert.fail = fail; -
ok
// 4. Pure assertion tests whether a value is truthy, as determined // by !!guard. // assert.ok(guard, message_opt); // This statement is equivalent to assert.equal(true, !!guard, // message_opt);. To test strictly for the value true, use // assert.strictEqual(true, guard, message_opt);. function ok(value, message) { if (!value) fail(value, true, message, "==", assert.ok); } assert.ok = ok; -
equal
// 5. The equality assertion tests shallow, coercive equality with // ==. // assert.equal(actual, expected, message_opt); assert.equal = function equal(actual, expected, message) { if (actual != expected) fail(actual, expected, message, "==", assert.equal); }; -
notEqual
// 6. 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); } }; -
deepEqual
// 7. The equivalence assertion tests a deep equality relation. // assert.deepEqual(actual, expected, message_opt); assert.deepEqual = function deepEqual(actual, expected, message) { if (!_deepEqual(actual, expected, false)) { fail(actual, expected, message, "deepEqual", assert.deepEqual); } }; ... -
notDeepEqual
// 8. The non-equivalence assertion tests for any deep inequality. // assert.notDeepEqual(actual, expected, message_opt); assert.notDeepEqual = function notDeepEqual(actual, expected, message) { if (_deepEqual(actual, expected, false)) { fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); } }; ...
总结、收获、感受
- Object.assign() 的使用。
- 最近在学 前端自动化测试 Jest 刚入门,那以后写自动化测试用例就可以用这个 assert 断言工具。
- 前段时间算是自己半吊子半截接手初次负责一个项目,改 bug 改了 8 天!改 🤮 了,一些感觉不重要的不想改,上头压着让赶紧弄完了下一个项目拖一天公司损失一天钱,测试又提 bug,改到后面边吐槽然后还是得改。最后周四晚上测试也留下加班必须得上线,后来她们说,该提的 bug 必须得提,不然到了客户那里发现问题客户就该说,这么简单的问题你们都没发现,那也许就晚了,嗯,是我疏忽了,经验不足,实力不足,还不想该 bug ,不行呀。然后就想,我得学会自动化测试,要是会了可能就规避掉了许多 bug 的出现,还有一些是改了之后出现的 bug。
- 到了接手新项目做完并测试完,这周已经交付客户在改客户新提出的新问题和需求了,有一个登录完弹框提示的流程,有一些限制条件,所以有些登录的用户是不会弹框的。而登录后用户信息等接口调用了两次,被后台大哥提了出来(那时还想多说,嗯,还是赶紧闭住嘴干活吧。),这是因为异步调用的问题(我的解决加了个调用时 pending 状态的标记,也可能以后会有其他更优解),解决了此问题,那个登录弹框的流程也被我改没了,今天发现改回来了。这不就是一个大问题么,必须得学会自动化测试,更加坚定了信心。
- 这种手动的容错率比较低,学自动化测试,交给机器来做吧。
- 此期源码阅读活动就适合我初次接触一下外面的世界-github 上优质项目,简单、易学、学会了有信心继续。
- 自动化测试很重要,加油吧!
最后
感谢 everyone ,踏踏实实,沉下心来,好好加油。
参考链接
【若川视野 x 源码共读】第 36 期 | 可能是历史上最简单的一期 omit.js 剔除对象中的属性