这是「🥬狗变形记」系列更新的第三天,今天给大家介绍一下让一个函数“模仿”另一个函数的NPM库 - 「mimic-fn」:
NPM:www.npmjs.com/package/mim…
先来看一看文档里的介绍:
mimic-fn能够让一个函数具备另一函数所用的名字和其他属性
看到简介,是不是觉得有点疑惑,函数的name我们都知道,那其他属性是包括哪些呢?🤔️以及mimic-fn主要做了什么呢? 在这里,我就直接给大家揭晓答案:
- 复制通过Reflect.ownKeys()获取到的属性
上图就是最简单函数得到的结果,其实实际场景中还可能存在其他自定义的一些属性
- 对toString方法进行了额外处理
- 改变了函数的原型指向
结合上面说到的mimic-fn做的事情,我们还是老规矩,先看下整体执行流程:
结合图片看源码里面每一步是怎么实现的:
整体流程:
function mimicFunction(to, from, {ignoreNonConfigurable = false} = {}) {
const {name} = to;
// 1. 处理属性
for (const property of Reflect.ownKeys(from)) {
copyProperty(to, from, property, ignoreNonConfigurable);
}
// 2. 改变原型指向
changePrototype(to, from);
// 3. 改变toString
changeToString(to, from, name);
return to;
}
其中每一步:
对Reflect.ownKeys获取到的属性处理:
const copyProperty = (to, from, property, ignoreNonConfigurable) => {
// 边界
if (property === 'length' || property === 'prototype') {
return;
}
// 边界
if (property === 'arguments' || property === 'caller') {
return;
}
const toDescriptor = Object.getOwnPropertyDescriptor(to, property);
const fromDescriptor = Object.getOwnPropertyDescriptor(from, property);
// 其实就是获取了属性描述符,做了一些判断
if (!canCopyProperty(toDescriptor, fromDescriptor) && ignoreNonConfigurable) {
return;
}
Object.defineProperty(to, property, fromDescriptor);
};
改变原型指向
Object.setPrototypeOf(to, fromPrototype);
改变toString
const changeToString = (to, from, name) => {
// with注释
const withName = name === '' ? '' : `with ${name.trim()}() `;
const newToString = wrappedToString.bind(null, withName, from.toString());
Object.defineProperty(newToString, 'name', toStringName);
// 设置to函数的toString属性
Object.defineProperty(to, 'toString', {...toStringDescriptor, value: newToString});
};
这里实际上就是用with包括了被模仿函数的toString执行后的结果,加上一行with注释
🤔️:这里我其实是对改变toString的作用不明确的,按理一个函数复制另外一个函数的属性,应该实际执行逻辑是不同,那toString的结果其实是函数的执行逻辑,这里有明白的小伙伴可以告诉我...
那我学到了什么呢?
- 关于Object对象上的各种用法:
- Object.keys:返回一个由一个给定对象的自身可枚举属性组成的数组(不包括Symbol)
- Object.getOwnPropertyNames() 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组
- Object.getOwnPropertySymbols 返回一个给定对象自身的所有 Symbol 属性的数组
- Reflect.ownKeys:返回一个由目标对象自身的属性键组成的数组。它的返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
- 属性描述符
- 数据属性描述符:value、writable
- 访问器/设置器属性描述符:get、set
- configurable:指定对象的属性描述可以被改变或者属性可被删除
- enumerable 可枚举
一些思考:
其实阅读源码的初衷就是为了“观看”分析别人写代码时候的考虑,选择,运用基础知识的能力,虽然mimic-func涉及到的知识都比较基础,但其中很多边界情况的判断,以及对基础知识的运用,也让自己更加明白:细节决定成败。⛽️GET UP!
🌊总结:
💪持续阅读好的代码库,思考学习好的代码,把自己的成长分享出来。
😊如果有一点点对你学习、工作、思考的帮助,我也会觉得很开心~