es-toolkit isFunction 完全指南:JavaScript 函数类型检测的原理与实战
2026/9/16 18:16:55 网站建设 项目流程

es-toolkit isFunction 完全指南:JavaScript 函数类型检测的原理与实战

【免费下载链接】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

isFunction是 es-toolkit 在predicate分类下提供的一个类型检测工具函数,用于判断给定值是否为函数。它覆盖普通函数、异步函数、生成器函数、构造函数以及各类 JavaScript 内置函数与类,在回调函数验证、动态函数调用等场景中扮演基础而关键的角色。阅读本文后,你将掌握isFunction的完整用法、TypeScript 类型收窄机制,以及它在 es-toolkit 内部被其他工具函数复用的底层原理。

函数签名与核心实现

isFunction的调用形式非常简单:

const result = isFunction(value);

其完整源码位于 src/predicate/isFunction.ts,整个实现只有一行,却蕴含着 TypeScript 类型收窄的关键设计:

export function isFunction(value: any): value is (...args: any[]) => any { return typeof value === 'function'; }

从源码可以提炼出三个核心事实:

  1. 判定依据是typeof运算符:JavaScript 中typeof对函数类型值返回字符串'function',这是语言层面的内置检测机制,任何函数(无论普通、异步、生成器还是构造函数)都会被命中;
  2. 返回类型是类型谓词(type predicate):返回值声明为value is (...args: any[]) => any,意味着在 TypeScript 中一旦isFunction(value)返回true,编译器就会把value的类型自动收窄为可调用函数,无需额外类型断言;
  3. 参数类型为any:它接受任意值,因此可以安全地用于检测来自外部输入、回调参数等不可信来源的值。

es-toolkit 还提供了与之等价的 lodash 兼容版本 src/compat/predicate/isFunction.ts,实现完全一致,并通过 src/browser.ts 在浏览器构建入口中导出,方便在浏览器环境下直接使用。

使用方法:检测所有类型的函数

isFunction的最大特点是覆盖面广,可以检测所有类型的函数。在 src/predicate/isFunction.spec.ts 的测试用例中,覆盖了普通函数、异步函数、生成器函数与Proxy构造函数等典型场景。

普通函数

import { isFunction } from 'es-toolkit/predicate'; // 普通函数 console.log(isFunction(function () {})); // true console.log(isFunction(() => {})); // true console.log(isFunction(Array.prototype.slice)); // true

其中Array.prototype.slice是方法引用(method reference),在 JavaScript 中方法本身也是函数,因此同样返回true

异步函数与生成器函数

// 异步函数 console.log(isFunction(async function () {})); // true console.log(isFunction(async () => {})); // true // 生成器函数 console.log(isFunction(function* () {})); // true

async函数与function*生成器虽然调用方式特殊,但它们的typeof结果依然是'function',因此会被正确识别。测试代码 src/predicate/isFunction.spec.ts 明确验证了这两类函数:

it('should return `true` for async functions', () => { const asyncFunc = async function () {}; expect(isFunction(asyncFunc)).toBe(typeof asyncFunc === 'function'); }); it('should return `true` for generator functions', () => { const genFunc = function* () {}; expect(isFunction(genFunc)).toBe(typeof genFunc === 'function'); });

构造函数

// 构造函数 console.log(isFunction(Array)); // true console.log(isFunction(Date)); // true console.log(isFunction(RegExp)); // true console.log(isFunction(Promise)); // true

ArrayDateRegExpPromise这些内置构造函数本质都是函数对象(需要配合new调用),因此全部返回true

检测内置 JavaScript 函数与类

isFunction同样适用于 JavaScript 内置的各类构造函数、类型化数组构造器以及 Proxy/Reflect 相关对象:

// 内置构造函数 console.log(isFunction(Object)); // true console.log(isFunction(String)); // true console.log(isFunction(Number)); // true console.log(isFunction(Boolean)); // true // 类型化数组构造函数 console.log(isFunction(Int8Array)); // true console.log(isFunction(Uint8Array)); // true console.log(isFunction(Float32Array)); // true // Proxy 与 Reflect console.log(isFunction(Proxy)); // true console.log(isFunction(Reflect.get)); // true

值得注意的是类型化数组构造器这一边界情况。在 src/predicate/isFunction.spec.ts 中,测试对Int8ArrayUint8ArrayUint8ClampedArrayInt16ArrayUint16ArrayInt32ArrayUint32ArrayFloat32ArrayFloat64Array以及DataView等全部类型化数组构造器逐一断言,其期望值与Object.prototype.toString.call(type) === '[object Function]'的结果逐项对齐。这表明isFunction的结果与标准标签检测(tag check)完全一致,行为可预期。

与"看起来像函数"的值区分开

isFunction只认typeof === 'function',因此对非函数值一律返回false

// 非函数值 console.log(isFunction({})); // false console.log(isFunction([])); // false console.log(isFunction('text')); // false console.log(isFunction(42)); // false console.log(isFunction(null)); // false console.log(isFunction(undefined)); // false // 看起来像函数但不是函数 console.log(isFunction({ call: function () {} })); // false

最后一例尤其值得注意:{ call: function () {} }拥有名为call的方法,外形上"可调用",但它是一个普通对象而非函数,typeof结果为'object',因此被正确判定为false。这正体现了isFunction严格基于语言级typeof语义、不做任何"长得像就算"的宽松推断。

在 src/predicate/isFunction.spec.ts 中,测试还利用falseyargs两个内部测试辅助(位于 src/compat/_internal 目录)对false0''nullundefinedNaN以及类数组arguments对象进行了批量验证,全部返回false;对象、数组、日期、错误、正则、字符串、数字、Symbol 等类型也逐一覆盖。

实战场景:回调验证与动态函数调用

场景一:回调函数的类型安全验证

在处理可选回调参数时,isFunction结合 TypeScript 类型谓词,可以消除"回调可能不是函数"的不确定性:

function processData(data: any[], callback?: unknown) { const result = data.map(item => item * 2); if (isFunction(callback)) { // 这里 callback 已被收窄为函数类型,可以安全调用 callback(result); } return result; }

由于isFunction的返回类型是value is (...args: any[]) => anyif分支内 TypeScript 编译器会自动将callback视为可调用函数,无需手动断言。

场景二:动态函数执行

当从配置、插件系统或用户输入中拿到一个"可能是函数"的值时,可以用它做动态分发:

function executeIfFunction(fn: unknown, ...args: any[]) { if (isFunction(fn)) { return fn(...args); } console.log('给定值不是函数'); return null; }

场景三:方法链中的函数确认

在链式 API 设计中,先用isFunction校验参数再执行映射,可以避免传入非法值时抛出难以定位的错误:

const utils = { data: [1, 2, 3], process(fn: unknown) { if (isFunction(fn)) { this.data = this.data.map(fn); } return this; }, };

参数与返回值

项目说明
参数value类型unknown,待检测是否为函数的任意值
返回值类型value is (...args: any[]) => any,值为函数时返回true,否则返回false

类型谓词签名意味着返回值同时承担"布尔判断"与"类型收窄"双重职责,这是 es-toolkit 谓词系列(如isStringisNumberisPlainObject等)共有的设计模式,统一通过 src/predicate/index.ts 对外导出。

在 es-toolkit 内部的实际复用

isFunction不只是独立工具,它还被 es-toolkit 内部多个高阶函数复用,这从侧面印证了它的可靠性与基础地位。在 lodash 兼容层 src/compat 中:

  • invokeMap.ts:当path本身是函数时,isFunction用于判断是直接调用还是走属性路径解析;
  • wrap.ts:用它决定wrapper参数是否为函数,否则回退为恒等函数(identity);
  • cond.ts:在条件函数列表中校验每个元素是否为函数;
  • bindAll.ts:过滤出对象上可绑定的函数属性;
  • functionsIn.ts:遍历对象属性时用isFunction筛选函数型属性;
  • transform.ts:判断对象构造器是否有效。

此外,memoize.spec.ts 等测试也会用isFunction来断言记忆化函数仍保持函数身份。这些内部使用点说明:isFunction是构建bindAllwrapcondinvokeMap等复合工具时的公共地基,其单行实现以typeof这一语言原语保证了极低的运行时开销——这也是 es-toolkit 追求"小而快"性能目标的一个缩影。

小结

isFunction用一行typeof value === 'function'实现了对所有函数类型的完备检测,并通过类型谓词让 TypeScript 开发者在运行时校验的同时获得编译期类型收窄。无论是处理可选回调、动态调用、方法链设计,还是理解 es-toolkit 内部wrapcondbindAll等函数的实现,它都是值得深入掌握的入门级但高频复用的工具函数。安装 es-toolkit 后,即可通过import { isFunction } from 'es-toolkit/predicate'直接使用。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询