JSCommon 前端常用数据处理工具库
JSCommon 介绍
JavaScript/TypeScript 的简单工具集合,为前端应用提供你所需要的全部工具函数
开始使用:
npm install @wolforest/jscommon
项目地址: github.com/wolforest/j…
JSCommon 数据处理工具库概览
Lodash:一致性、模块化、高性能的 JavaScript 实用工具库
Lodash 是当前最流行的 JavaScript 工具库之一,它通过提供大量实用的工具函数,帮助开发者更轻松地处理数组、数字、对象、字符串等数据。
为什么选择 Lodash?
- 可靠性:
- 经过充分测试
- 社区活跃,持续维护
- 在 GitHub 上拥有超过 50k 的 star
- 性能优化:
- 优化的内部实现
- 支持按需引入
- 链式调用优化
- 一致性:
- 跨浏览器兼容
- 统一的 API 设计
- 可预测的函数行为
安装和使用
# npm 安装
npm install lodash
# yarn 安装
yarn add lodash
引入方式:
// 全量引入
import _ from 'lodash';
// 按需引入(推荐)
import get from 'lodash/get';
import debounce from 'lodash/debounce';
核心功能详解
1. 数组操作
// 数组分块
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
// 数组去重
_.uniq([2, 1, 2, 3, 1]);
// => [2, 1, 3]
// 数组扁平化
_.flatten([1, [2, [3, [4]], 5]]);
// => [1, 2, [3, [4]], 5]
// 深度扁平化
_.flattenDeep([1, [2, [3, [4]], 5]]);
// => [1, 2, 3, 4, 5]
2. 对象操作
const obj = { a: [{ b: { c: 3 } }] };
// 安全获取深层属性
_.get(obj, 'a[0].b.c', 'default');
// => 3
// 属性不存在时返回默认值
_.get(obj, 'a[0].b.d', 'default');
// => 'default'
3. 函数优化
// 创建防抖函数
const debouncedSave = _.debounce(function(text) {
console.log('保存:', text);
}, 1000);
// 创建节流函数
const throttledScroll = _.throttle(function() {
console.log('滚动事件处理');
}, 100);
4. 字符串处理
// 首字母大写
_.capitalize('hello world');
// => 'Hello world'
// 驼峰转换
_.camelCase('hello-world');
// => 'helloWorld'
最佳实践
- 按需引入
// 好的做法
import get from 'lodash/get';
import debounce from 'lodash/debounce';
// 避免这样做
import _ from 'lodash';
- 使用类型检查
// 配合 TypeScript 使用
import { get } from 'lodash';
const value = get<string>(obj, 'path', 'default');
Immer:不可变数据处理利器
Immer 是一个能让你以更直观的方式处理不可变数据的 JavaScript 库。它的核心理念是通过修改当前状态的副本(draft)来生成下一个不可变状态,这使得复杂的状态更新变得简单直观。
为什么选择 Immer?
1. 主要优势
- 直观的可变式写法
- 自动处理不可变性
- 更少的样板代码
- 优秀的性能表现
- 结构共享优化
- TypeScript 友好
2. 适用场景
- React 状态管理
- Redux reducer 编写
- 复杂数据结构更新
- 嵌套对象的处理
基础使用
import produce from 'immer';
// 基础示例
const baseState = {
users: [{id: 1, name: 'John'}],
settings: {
theme: 'light'
}
};
const nextState = produce(baseState, draft => {
// 直接修改 draft
draft.users.push({id: 2, name: 'Jane'});
draft.settings.theme = 'dark';
});
// baseState 保持不变
console.log(baseState.users.length); // 1
// nextState 包含新的更改
console.log(nextState.users.length); // 2
核心功能详解
1. 对象操作
const baseState = {
name: 'John',
age: 30,
address: {
city: 'New York',
country: 'USA'
}
};
const nextState = produce(baseState, draft => {
// 修改属性
draft.name = 'Jane';
// 修改嵌套属性
draft.address.city = 'Boston';
// 添加新属性
draft.email = 'jane@example.com';
// 删除属性
delete draft.age;
});
2. 数组操作
const baseState = {
todos: [
{ id: 1, text: '学习 React', done: false },
{ id: 2, text: '学习 Immer', done: false }
]
};
const nextState = produce(baseState, draft => {
// 添加元素
draft.todos.push({ id: 3, text: '学习 Redux', done: false });
// 删除元素
draft.todos.splice(0, 1);
// 修改元素
const todo = draft.todos.find(todo => todo.id === 2);
if (todo) {
todo.done = true;
}
});
实际应用场景
React 状态管理
import { useState } from 'react';
import produce from 'immer';
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: '学习 React', done: false }
]);
const addTodo = text => {
setTodos(produce(draft => {
draft.push({ id: Date.now(), text, done: false });
}));
};
const toggleTodo = id => {
setTodos(produce(draft => {
const todo = draft.find(todo => todo.id === id);
if (todo) {
todo.done = !todo.done;
}
}));
};
}
Ramda:函数式编程工具库
Ramda 是一个专注于函数式编程范式的 JavaScript 工具库。与 Lodash 等库不同,Ramda 的特点是所有函数都是自动柯里化的,且遵循数据不可变原则。
为什么选择 Ramda?
1. 函数式编程特性
- 自动柯里化(Currying)
- 数据不可变性(Immutability)
- 函数组合(Composition)
- Point-free 编程风格
- 参数顺序优化(data-last)
2. 相比其他库的优势
- 专注于函数式编程
- 纯函数设计
- 更好的函数组合支持
- 更适合函数式编程范式
安装和使用
# npm 安装
npm install ramda
# yarn 安装
yarn add ramda
引入方式:
// 全量引入
import * as R from 'ramda';
// 按需引入(推荐)
import { pipe, map, filter } from 'ramda';
核心概念详解
1. 柯里化(Currying)
// 基础柯里化示例
const add = R.add;
const add5 = add(5);
add5(3); // => 8
// 多参数柯里化
const multiply = R.multiply;
const double = multiply(2);
double(4); // => 8
2. 函数组合
const calculateFinalScore = R.pipe(
R.prop('scores'), // 获取分数数组
R.sum, // 求和
R.divide(R.__, 100), // 除以100
R.multiply(10) // 乘以10
);
const student = { scores: [70, 80, 90] };
calculateFinalScore(student); // => 24
3. 数据处理
// 过滤和映射
const numbers = [1, 2, 3, 4, 5];
const isEven = x => x % 2 === 0;
const double = x => x * 2;
const processNumbers = R.pipe(
R.filter(isEven),
R.map(double)
);
processNumbers(numbers); // => [4, 8]
最佳实践
Point-free 风格
// 不好的写法
const getTotal = data => R.sum(R.map(R.prop('amount'), data));
// 好的写法(Point-free)
const getTotal = R.pipe(
R.map(R.prop('amount')),
R.sum
);
Big.js:JavaScript 精确数学计算库
Big.js 是一个用于任意精度十进制算术的 JavaScript 库。它解决了 JavaScript 处理浮点数计算时的精度问题,特别适合金融计算等对精度要求较高的场景。
基础使用
基本运算
import Big from 'big.js'
// 加法
const sum = new Big('0.1')
.plus('0.2')
.toString() // '0.3'
// 减法
const difference = new Big('0.3')
.minus('0.1')
.toString() // '0.2'
// 乘法
const product = new Big('0.1')
.times('0.2')
.toString() // '0.02'
// 除法
const quotient = new Big('0.3')
.div('0.1')
.toString() // '3'
精度控制
import Big from 'big.js'
// 设置全局配置
Big.DP = 20 // 小数位数
Big.RM = 1 // 舍入模式 (0-3)
// 四舍五入到指定小数位
const num = new Big('1.23456789')
console.log(num.round(2).toString()) // '1.23'
高级特性
金融计算
class FinancialCalculator {
// 计算复利
static calculateCompoundInterest(
principal: string,
rate: string,
years: number,
compoundingFrequency: number = 1
): string {
const p = new Big(principal)
const r = new Big(rate).div(100)
const n = new Big(compoundingFrequency)
const t = new Big(years)
// A = P(1 + r/n)^(nt)
return p.times(
new Big(1)
.plus(r.div(n))
.pow(n.times(t))
).round(2).toString()
}
}
Number-Precision:JavaScript 精确数值计算库
number-precision 是一个轻量级的精确数值计算库,用于解决 JavaScript 中浮点数计算的精度问题。
精度问题本质
JavaScript 中的数字采用 IEEE 754 双精度浮点数标准,这导致了一些著名的精度问题:
0.1 + 0.2 = 0.30000000000000004
1.0 - 0.9 = 0.09999999999999998
0.105.toFixed(2) = '0.11'
这些问题源于二进制无法精确表示某些十进制小数,就像十进制无法精确表示 1/3 一样。
快速使用
import NP from 'number-precision'
// 去除浮点数计算误差
NP.strip(0.09999999999999998) // = 0.1
// 加法运算
NP.plus(0.1, 0.2) // = 0.3
NP.plus(2.3, 2.4) // = 4.7
// 减法运算
NP.minus(1.0, 0.9) // = 0.1
// 乘法运算
NP.times(3, 0.3) // = 0.9
实践应用
金融计算
class FinancialCalc {
// 计算利息
static calculateInterest(
principal: number,
rate: number,
years: number
): number {
return NP.times(
principal,
rate / 100,
years
);
}
}
@wolforest/jscommon 数据处理架构设计与实现
@wolforest/jscommon 是一个统一的 JavaScript/TypeScript 工具库,它集成了上述多个常用的数据处理库,并提供了一致的 API 接口。通过这种方式,开发者可以使用一个依赖获得多个库的能力,同时享受粗颗粒度的 Tree-shaking 支持。
架构设计
@wolforest/jscommon 采用模块化设计,按功能领域划分不同的工具类:
-
lang 模块:核心语言增强
- ArrayUtil:数组操作工具
- ObjectUtil:对象操作工具
- StringUtil:字符串操作工具
- NumberUtil:数字操作工具
- DecimalUtil:精确数值计算工具
- DateUtil:日期处理工具
- FunctionUtil:函数工具
- TypeUtil:类型判断工具
- JSONUtil:JSON 处理工具
-
storage 模块:存储相关工具
-
net 模块:网络请求工具
-
style 模块:样式处理工具
-
debug 模块:调试工具
编码实现
以 DecimalUtil 为例,它封装了 Big.js 库,提供精确数值计算能力:
import Big from 'big.js';
export class DecimalUtil {
// 创建 Big 实例
static of(value: number | string): Big {
return new Big(value);
}
// 精确加法
static add(...numbers: (number | string)[]): string | number {
return numbers.reduce((sum, num) => new Big(sum).plus(num).toString());
}
// 精确减法
static subtract(minuend: number | string, subtrahend: number | string): string {
return new Big(minuend).minus(subtrahend).toString();
}
// 精确乘法
static multiply(...numbers: (number | string)[]): string | number {
return numbers.reduce((product, num) => new Big(product).times(num).toString());
}
// 精确除法
static divide(dividend: number | string, divisor: number | string, precision: number = 10): string {
if (new Big(divisor).eq(0)) {
throw new Error('Division by zero');
}
return new Big(dividend).div(divisor).toFixed(precision);
}
}
ObjectUtil 则封装了 Lodash 的对象操作能力:
import {
assign, merge, get, pick, omit, cloneDeep, isEqual
// ...其他 lodash 函数
} from 'lodash-es';
export class ObjectUtil {
static assign = assign;
static merge = merge;
static get = get;
static pick = pick;
static omit = omit;
static cloneDeep = cloneDeep;
static isEqual = isEqual;
// ...其他方法
}
使用示例
import { ObjectUtil, DecimalUtil } from '@wolforest/jscommon';
// 对象操作
const obj = { a: { b: { c: 1 } } };
const value = ObjectUtil.get(obj, 'a.b.c', 0); // 1
// 精确数值计算
const price = DecimalUtil.multiply('10.5', '2'); // "21"
const total = DecimalUtil.add('99.9', '0.1'); // "100"
通过这种设计,@wolforest/jscommon 实现了:
- 统一的 API 入口:所有工具函数通过统一的命名空间访问
- 粗颗粒度的 Tree-shaking 支持:按需引入,减少打包体积
- 类型安全:完整的 TypeScript 类型定义
- 功能分类清晰:按功能模块组织代码
- 扩展性强:可以方便地添加新的工具函数和模块
这种架构使得开发者可以用统一的方式访问多个库的能力,简化了项目依赖管理,提高了开发效率。
项目地址: github.com/wolforest/j…
感谢阅读到最后,期待你的 github 🌟 鼓励!