likes
comments
collection
share

又来了一个工具库 es-toolkit - 和 Lodash 对比一下

作者站长头像
站长
· 阅读数 22

前端的工具库,最早的热门库为 Underscore,后来 Lodash 逐渐替代 Underscore,成为了主流工具库。Lodash 的灵感来源于 Underscore,在随后的迭代中,Lodash 的功能、兼容性、模块化能力、社区生态都超过了 Underscore,基本是前端项目的工具集标配,除了 Lodash, Ramda 是另外一个比较热门的工具库。

不过 Lodash 的最新版本发布是在三年前,在前端生态喜欢不断推新和 ES 语法每年都有在更新的推动下,新的更现代化工具集库就开始出现了,比如 Radash 和 es-toolkit 等等。Radash 的 1.0.0 版本是在三年前发布,现在已更新到 12.1.0,而 es-toolkit 的第一个版本发布仅仅是两个月前。

Radash 的特点是:

  • 它是用 Typescript 编写的
  • 源码中使用的语法更加的新
  • 提供了一些 Lodash 没有的实用方法(tryit、parallel、retry 等等)

本文主要介绍 es-toolkit 的特点。

es-toolkit 的特点

es-toolkit 的特点有:

  • 通过其现代化的实现,es-toolkit 显著减少了其包体积,与 Lodash 等其他库相比,可以减少高达 97%。
  • es-toolkit 设计时考虑了性能,与类似 Lodash 的替代库相比,平均性能提升了2倍。
  • 全面的运行时支持,除了 Web 和 Node,还支持了 Bun、Deno 运行环境,可以通过 JSR 安装到 Deno。

打包体积

官方给出的相关方法的打包体积数据,可以看到 es-toolkit 打包体积小了很多。

又来了一个工具库 es-toolkit - 和 Lodash 对比一下

但是你要是实际去看看两边的 API 能力,就会发现这个数据有些水分,从下图就可以看出 Lodash 的 debounce 支持的能力更多。

又来了一个工具库 es-toolkit - 和 Lodash 对比一下

接着来看下 es-toolkit 的 debounce 源码:

export function debounce<F extends (...args: any[]) => void>(
  func: F,
  debounceMs: number,
  { signal }: DebounceOptions = {}
): F & { cancel: () => void } {
  let timeoutId: number | null = null;

  const debounced = function (...args: Parameters<F>) {
    if (timeoutId !== null) {
      clearTimeout(timeoutId);
    }

    if (signal?.aborted) {
      return;
    }

    timeoutId = setTimeout(() => {
      func(...args);
      timeoutId = null;
    }, debounceMs) as any;
  } as F & { cancel: () => void };

  const onAbort = function () {
    debounced.cancel();
  };

  debounced.cancel = function () {
    if (timeoutId !== null) {
      clearTimeout(timeoutId);
      timeoutId = null;
    }
  };

  signal?.addEventListener('abort', onAbort, { once: true });

  return debounced;
}

可以看到 es-toolkit 的 debounce 源码相对比较简单,其中 cancel 方法是通过外部传入一个 AbortController 示例来完成的,API 是比较现代化,但是使用上却没有 Lodash 方便。

// lodash cancel debounce
const lodashDeounceFn = lodash.debounce(() => console.log(1), 250);
lodashDeounceFn();
lodashDeounceFn.cancel()

// es-toolkit cancel debouce
const controller = new AbortController();
const signal = controller.signal;
const debouncedWithSignalFunction = debounce(() => console.log(1), 250, { signal });
// 如果在此期间没有再次调用,则在1秒后输出 'Function executed'
debouncedWithSignalFunction();
// 取消了防抖函数的调用
controller.abort();

性能对比

官方给的性能对比数据:

又来了一个工具库 es-toolkit - 和 Lodash 对比一下

和打包体积类似,虽然 es-toolkit 的 omit 方法性能更高,但是两边支持的能力其实是不太一样的。

又来了一个工具库 es-toolkit - 和 Lodash 对比一下

Lodash 的 omit 方法可以支持深层的对象属性忽略,而 es-toolkit 只能是第一层属性的忽略。

// es-toolkit 的源码
export function omit<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
  const result = { ...obj };

  for (const key of keys) {
    delete result[key];
  }

  return result as Omit<T, K>;
}

// es-toolkit 的 omit 的使用
omit({ a: { b: 1 }, c: 2 }, ['a.b', 'c']);
// 返回是 { a: { b: 1 } }

// lodash 的 omit 的使用
lodash.omit({ a: { b: 1 }, c: 2 }, ['a.b', 'c']);
// 返回 { a: {} }

es-toolkit 中的一些方法

flattenObject

扁平化的对象。

const nestedObject = {
  a: {
    b: {
      c: 1
    }
  },
  d: [2, 3]
};

const flattened = flattenObject(nestedObject);
console.log(flattened); 
// 输出:
// {
//   'a.b.c': 1,
//   'd.0': 2,
//   'd.1': 3
// }

camelCase

字符串转换为驼峰命名法

import { camelCase } from 'es-toolkit/string';

camelCase('camelCase'); // 返回 'camelCase'
camelCase('some whitespace'); // 返回 'someWhitespace'
camelCase('hyphen-text'); // 返回 'hyphenText'
camelCase('HTTPRequest'); // 返回 'httpRequest'

delay

延迟执行代码指定的毫秒数,支持一个可选的 AbortSignal 来取消延迟。

async function foo() {
  const controller = new AbortController();
  const signal = controller.signal;

  setTimeout(() => controller.abort(), 50); // 在 50 毫秒后取消延迟
  try {
    await delay(1000, { signal });
  } catch (error) {
    console.log(error); // 将会输出 'The operation was aborted'
  }
}

拓展

无论是 Radash 还是 es-toolkit,提供的 clone 方法都是浅复制,深复制的话就要使用 JS 原生的现代化方法 structuredClone。不过 structuredClone 不能复制函数和 DOM 节点等等,如果要复制的对象中包括此类属性,方法就会抛出异常,相对来说 Lodash 的复制方法功能更强大,使用也更方便。

const obj = { n: 2 }
const objWithFn = { n: 2, f: () => console.log(1) }
const fn = () => { console.log('fn') }

// lodash
_.cloneDeep(obj) // 返回 { n: 2 }
_.cloneDeep(objWithFn).f() // 输出 1
_.cloneDeep(fn) // 返回 {}

// 原生方法
structuredClone(obj)
// 返回 { n: 2 }
structuredClone(objWithFn)
// Uncaught DOMException: Failed to execute 'structuredClone' on 'Window'
structuredClone(fn)
// Uncaught DOMException: Failed to execute 'structuredClone' on 'Window'

不过你使用 Radash 或者 es-toolkit 的话,也是可以单独安装 Lodash 的 CloneDeep, 对应包为 lodash.clonedeep

总结

es-toolkit 相比与 Lodash 来说,还是有很长一段路要走,毕竟第一个版本是两个月前。不过 es-toolkit 中是有在用更现代化的 API,如果你这些感兴趣,可以参与 es-toolkit 的开源建设。

整体来看,喜欢尝鲜的可以在小项目试试 es-toolkit,其他情况还是建议使用 Lodash,或者可以使用 Radash。

转载自:https://juejin.cn/post/7395022563976904742
评论
请登录