老渔哥网站建设公司,河南睢县筑宇建设网站,网站购买广告位,三合一模板网站1. 项目初始化
首先#xff0c;我们需要为开源库取一个名字#xff0c;并确保该名字在 npm 上没有被占用。假设我们选择的名字是 jstoolpack#xff0c;并且已经确认该名字在 npm 上不存在。
mkdir jstoolpack
cd jstoolpack
npm init -y2. 安装依赖
接下来#xff0c;我…1. 项目初始化
首先我们需要为开源库取一个名字并确保该名字在 npm 上没有被占用。假设我们选择的名字是 jstoolpack并且已经确认该名字在 npm 上不存在。
mkdir jstoolpack
cd jstoolpack
npm init -y2. 安装依赖
接下来我们需要安装一些开发和测试依赖。我们将使用 TypeScript 进行开发并使用 Jest 进行单元测试。
devDependencies: {types/jest: ^29.5.1,jest: ^29.5.0,jest-environment-jsdom: ^29.5.0,ts-jest: ^29.1.0,ts-node: ^10.9.1,typescript: ^5.0.4
}npm i types/jest jest jest-environment-jsdom ts-jest ts-node typescript -D3. 项目结构
在项目根目录下创建 src源码目录和 tests测试目录。项目本身不难该项目是一个类似于 lodash 的工具库项目会对常见的 array、function、string、object 等提供一些工具方法。
mkdir src tests4. 配置 TypeScript
在项目根目录下创建 tsconfig.json 文件配置 TypeScript 编译选项。
{compilerOptions: {target: es6,module: commonjs,strict: true,esModuleInterop: true,skipLibCheck: true,forceConsistentCasingInFileNames: true,outDir: ./dist,rootDir: ./src,baseUrl: .,paths: {*: [node_modules/*]}},include: [src/**/*.ts],exclude: [node_modules, dist]
}5. 配置 Jest
在项目根目录下创建 jest.config.js 文件配置 Jest 测试框架。
module.exports {preset: ts-jest,testEnvironment: jsdom,roots: [rootDir/tests],transform: {^.\\.tsx?$: ts-jest,},moduleFileExtensions: [ts, tsx, js, jsx, json, node],
};6. 开发工具方法
6.1 range 方法
这里我们打算扩展一个名为 range 的方法该方法可以生成指定范围的数组
range(1, 6) --- [1, 2, 3, 4, 5] 左闭右开
range(1, 6, 2) --- [1, 3, 5]
range(1, 6, -2) --- [1, 3, 5]range(6, 1) --- [6, 5, 4, 3, 2]
range(6, 1, -2) --- [6, 4, 2]
range(6, 1, 2) --- [6, 4, 2]对应的源码如下
// 理论上来讲start,stop,step 都应该是 number 类型
// 但是我们的代码最终是打包为 js 给开发者使用
// 开发者可能会存在各种非常的调用 range() range(a,b,c)
// 因此我们这里打算从方法内部进行参数防御从而提升我们代码的健壮性
export function range(start?: any, stop?: any, step?: any) {// 参数防御start start ? (isNaN(start) ? 0 : start) : 0;stop stop ? (isNaN(stop) ? 0 : stop) : 0;step step ? (isNaN(step) ? 0 : step) : 1;// 保证 step 的正确if ((start stop step 0) || (start stop step 0)) {step -step;}const arr: number[] [];for (let i start; start stop ? i stop : i stop; i step) {arr.push(i);}return arr;
}
对应的测试代码如下
import { range } from ../src/array;test(正常的情况, () {expect(range(1, 6)).toEqual([1, 2, 3, 4, 5]);expect(range(1, 6, 2)).toEqual([1, 3, 5]);expect(range(6, 1)).toEqual([6, 5, 4, 3, 2]);expect(range(6, 1, -2)).toEqual([6, 4, 2]);
});test(错误的情况, () {expect(range()).toEqual([]);expect(range(a, b, c)).toEqual([]);
});test(测试只传入start, () {// 相当于结束值默认为 0expect(range(2)).toEqual([2, 1]);expect(range(-2)).toEqual([-2, -1]);
});test(测试step, () {expect(range(1, 6, -2)).toEqual([1, 3, 5]);expect(range(6, 1, 2)).toEqual([6, 4, 2]);
});6.2 truncate 方法
这里我们打算提供了一个 truncate 的方法有些时候字符串过长那么我们需要进行一些截取
truncate(1231323423424, 5) ---- 12...
truncate(12345, 5) ---- 12345
truncate(1231323423424, 5, -) ---- 1231-对应的源码如下
export function truncate(str?: any, len?: any, omission ...) {// 内部来做参数防御str String(str);omission String(omission);len len ? Math.round(len) : NaN;if (isNaN(len)) {return ;}if (str.length len) {// 说明要开始截断str str.slice(0, len - omission.length) omission;}return str;
}对应的测试代码如下
import { truncate } from ../src/string;test(应该将字符串截取到指定长度, () {expect(truncate(Hello World, 5)).toBe(He...);expect(truncate(Hello World, 10)).toBe(Hello W...);expect(truncate(Hello World, 11)).toBe(Hello World);expect(truncate(Hello World, 15)).toBe(Hello World);expect(truncate(1231323423424, 5)).toBe(12...);expect(truncate(12345, 5)).toBe(12345);expect(truncate(1231323423424, 5, -)).toBe(1231-);
});test(如果长度参数不是一个数字那么返回一个空字符串, () {expect(truncate(Hello World, NaN)).toBe();expect(truncate(Hello World, abc as any)).toBe();
});test(应该正确处理空字符串和未定义的输入, () {expect(truncate(, 5)).toBe();expect(truncate(undefined, 5)).toBe(un...);
});test(应该正确处理省略号参数, () {expect(truncate(Hello World, 5, ...)).toBe(He...);expect(truncate(Hello World, 10, ---)).toBe(Hello W---);
});test(始终应该返回一个字符串, () {expect(typeof truncate(Hello World, 5)).toBe(string);expect(typeof truncate(Hello World, NaN)).toBe(string);expect(typeof truncate(undefined, 5)).toBe(string);
});6.3 debounce 方法
函数防抖是一个很常见的需求我们扩展一个 debounce 方法可以对传入的函数做防抖处理
对应的代码如下
type FuncType (...args: any[]) any;
export function debounceT extends FuncType(func: T,wait: number
): (...args: ParametersT) void {let timerId: ReturnTypetypeof setTimeout | null null;return function (...args: ParametersT): void {if (timerId) {clearTimeout(timerId);}timerId setTimeout(() {func(...args);}, wait);};
}对应的测试代码如下
import { debounce } from ../src/function;beforeEach(() {jest.useFakeTimers();
});afterEach(() {jest.clearAllTimers();jest.useRealTimers();
});test(应该在等待时间之后调用函数,(){const func jest.fn();const debouncedFunc debounce(func, 1000);debouncedFunc();jest.advanceTimersByTime(500);expect(func).toHaveBeenCalledTimes(0);jest.advanceTimersByTime(500);expect(func).toHaveBeenCalledTimes(1);
})test(当防抖函数执行的时候始终只执行最后一次的调用,(){const func jest.fn();const debouncedFunc debounce(func, 1000);debouncedFunc(a);debouncedFunc(b);debouncedFunc(c);jest.advanceTimersByTime(1000);expect(func).toHaveBeenCalledWith(c);
})test(在等待时间内又调用了函数重置计时器,(){const func jest.fn();const debouncedFunc debounce(func, 1000);debouncedFunc();jest.advanceTimersByTime(500);debouncedFunc();jest.advanceTimersByTime(500);expect(func).toHaveBeenCalledTimes(0);jest.advanceTimersByTime(1000);expect(func).toHaveBeenCalledTimes(1);
})7. 运行测试
在 package.json 中添加一个测试脚本。
{scripts: {test: jest}
}运行测试命令
npm test8. 构建和发布
在 package.json 中添加构建脚本。
{scripts: {build: tsc,test: jest}
}构建项目
npm run build发布到 npm
npm login
npm publish总结
通过以上步骤我们成功地搭建了一个简单的 JavaScript 工具库项目 jstoolpack并实现了 range、truncate 和 debounce 三个常用工具方法。我们使用了 TypeScript 进行类型检查并使用 Jest 进行单元测试确保代码的健壮性和可靠性。最后我们通过 npm 发布了这个工具库使其可以被其他开发者使用。