es-toolkit/compat 的 method:预创建按路径调用对象方法的函数
【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit
method是 es-toolkit 兼容层(es-toolkit/compat)中与 Lodash 完全对齐的工具函数,它接收一个属性路径和若干预设参数,返回一个"等待对象"的高阶函数:把这个返回函数传给任意对象,就会在指定路径上以正确的this绑定调用该对象上的方法,并把预设参数原样传入。读完本文,你能掌握method的参数与返回值语义、它在函数式编程和Array.map等场景中的典型用法,以及从源码层面理解其路径解析、this绑定与空值处理的完整实现链路。
什么是 method:方法调用的柯里化封装
在函数式编程中,经常需要"先固定调用方式,后传入接收者"。比如要对一组对象逐个调用obj.calc.sum(5, 3),直接写匿名函数略显啰嗦。method将「路径 + 参数」部分应用(partial application)掉,剩下的object参数延迟到调用时才提供:
const methodFunc = method(path, ...args);这与 Lodash 的_.method行为一致,是 es-toolkit/compat 兼容层 的一部分——该层 1:1 镜像 Lodash 的接口与行为,自 v1.39.3 起通过 Lodash 官方测试套件,因此从lodash迁移过来时调用点无需改动。
基本用法与参数说明
函数签名为method(path, ...args):
path(PropertyKey | PropertyKey[]):要调用的方法的路径。可以是点分字符串('a.b')、键数组(['a', 'b'])、数字索引或 symbol;...args(any[]):调用方法时传入的参数,在创建函数时一次性固定;- 返回值:一个
(object: any) => any函数,调用时接收目标对象,在其path路径处取出方法并连同args一起执行。
import { method } from 'es-toolkit/compat'; const object = { a: { b: function (x, y) { return x + y; }, }, }; // 创建一个方法调用函数 const add = method('a.b', 1, 2); console.log(add(object)); // => 3 // 对数组中每个对象调用相同路径的方法 const objects = [{ calc: { sum: (a, b) => a + b } }, { calc: { sum: (a, b) => a * b } }]; const calculate = method('calc.sum', 5, 3); objects.map(calculate); // => [8, 15]第二个例子展示了它的核心优势:method('calc.sum', 5, 3)生成一个可复用的一等函数,直接交给map,避免为每个元素重复书写调用逻辑。
嵌套路径与 this 绑定
method同样支持嵌套路径。值得注意的一点是:被测方法内部访问this.name,而调用结果依然是'Mr. John',说明this被正确绑定到了方法所在的父对象,而非全局环境:
import { method } from 'es-toolkit/compat'; const obj = { users: { getName: function (prefix) { return prefix + this.name; }, name: 'John', }, }; const getUserName = method('users.getName', 'Mr. '); getUserName(obj); // => 'Mr. John'这一点在测试中也有专门验证:method.spec.ts 中 "should invoke deep property methods with the correctthisbinding" 用例断言{ a: { b() { return this.c; }, c: 1 } }上method('a.b')的调用结果为1。
源码实现:method 只是 invoke 的柯里化外壳
method.ts 的实现极为简洁——它本身不解析路径,只是把参数固化进闭包,把真正的路径解析与调用交给invoke:
export function method(path: PropertyKey | readonly PropertyKey[], ...args: any[]): (object: any) => any { return function (object?: unknown) { return invoke(object, path, args); }; }真正的工作量在 invoke.ts 中。整个调用链可以概括为:
参数展平:
invoke入口先执行args = args.flat(1),以兼容"传一个数组当参数列表"的 Lodash 习惯写法;空值守卫:
object == null时直接返回undefined,不会抛出异常;路径分流(invoke.ts):
path为字符串时,先检查对象是否直接拥有该字符串键(Object.hasOwn)。若有,则按单一键处理;否则交给 toPath 解析点分/方括号深路径('a.b'→['a', 'b'],'a["b.c"]'→['a', 'b.c']);path为数字或 symbol 时作为单段键直接使用;path为数组时逐段使用,其他类型则包装成单段。
这个"直接键优先于路径"的策略有对应测试:"should use a key over a path" 用例中,对象同时含有
'a.b'键和a.b嵌套,method('a.b')命中的是扁平键。父对象定位与方法执行(invokeImpl):用
get(object, path.slice(0, -1), object)取到方法的父对象(路径缺失时得到undefined,整体返回undefined),再把最后一段键取出方法并执行func?.apply(parent, args)——apply的第二参数parent正是this绑定正确的来源。
另外从测试可以看到,path支持隐式类型强制:"should coercepathto a string" 用例中,null、undefined、自定义toString的函数、普通对象分别被强制为'null'、'undefined'、'fn'、'[object Object]'后作为键使用;继承属性(原型链上的方法)同样可以被调用,这与 Lodash 行为一致。
边界行为一览(均有测试佐证)
以下行为均可在 method.spec.ts 中找到对应断言,迁移 Lodash 代码时可以放心依赖:
| 场景 | 行为 | 依据用例 |
|---|---|---|
深路径('a.b'/['a','b']) | 正常调用,字符串与数组路径等价 | "should work with deep property values" |
数字路径(如method(array, 1)) | 视为数组索引键 | "should work with a non-stringpath" |
| 原型链上的方法 | 可被调用(含继承查找) | "should work with inherited property values" |
对象为null/undefined/ 未传 | 返回undefined,不抛错 | "should returnundefinedwhenobjectis nullish" |
| 路径中间段缺失 | 返回undefined | "should returnundefinedif parts ofpathare missing" |
| 部分应用参数 | 创建时的...args原样传给方法 | "should apply partial arguments to function" |
与 methodOf 的对比:谁在前,谁在后
method与 methodOf 共享同一个invoke内核,只是柯里化的方向相反:
method(path, ...args)→ 返回函数接收object:适合"对一组不同对象调用同一方法"(本文开头的map场景);methodOf(object, ...args)→ 返回函数接收path:适合"对同一个对象按不同路径调用方法"。
选择哪个取决于变化量在哪一侧:接收者集合固定时用methodOf,路径与参数固定时用method。
引入方式与迁移建议
method位于 compat 子包,标准引入方式:
import { method } from 'es-toolkit/compat';在无 tree-shaking 环境(CommonJSrequire()、React Native、无打包器的 Node.js 脚本)中,也可以按需引入单函数入口,只加载该函数依赖的文件:
import method from 'es-toolkit/compat/method'; // 或 const method = require('es-toolkit/compat/method');对于正在从 Lodash 迁移的项目,推荐路径是先整体替换导入为es-toolkit/compat保持调用点不动,再逐步整理为严格的es-toolkitAPI;对于新项目且本就不依赖 Lodash,则可直接使用es-toolkit主包。method这类高阶函数在两种包中的位置不同(compat 面向迁移对齐),选型时留意这一点即可。
本文参考的文档与代码:method 兼容文档、method 实现、invoke 实现、methodOf 实现、toPath 实现、method 测试、compat 包说明。
【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考