一些实用的小方法
查找是否含有子序列
function isFuzzMatch(lq,sq){
let j=0;
for(let i=0;i<lq.length;i++){
if(lq[i]===sq[j]){
j++
}else{
j=0;
}
}
return j===sq.length;
}
isFuzzMatch("h", "e", "l", "l", "o"],["e", "l", "o"])将数字转为会计计数
不带货币单位
function formatCurrency(num){
return num.toLocalString('zh-CN')
}
formatCurrency(1000)带货币单位
function formatCurrency(num) {
return num.toLocaleString("zh-CN", {
style: "currency",
currency: "CNY",
});
}
formatCurrency(1000);正则表达
function formatCurrency(num) {
let [intPart, decPart] = Math.abs(num).toFixed(2).split("."); // 保留2位小数
intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ","); // 千分位
return (num < 0 ? "-" : "") + intPart + "." + decPart;
}
formatCurrency(1000);查找重复元素
function findDuplicates(arr){
const hash=new Map();
const duplicates=new Set();
for(let i of arr){
if(hash.has(i)){
duplicates.add(i)
}
hash.set(i,true)
}
return Array.from(duplicates)
}
findDuplicates([1, 2, 3, 4, 5, 2, 3, 6, 7, 3])数组去重
new Set
function uniq(arr) {
return Array.from(new Set(arr));
}
uniq([1, 1, 1, 2, 2]);filter
function uniq(arr) {
return arr.filter((item, index) => arr.indexOf(item) === index);
}
uniq([1, 1, 1, 2, 2]);对象数组使用Map去重
function uniq(arr, key) {
return Array.from(new Map(arr.map((item) => [item[key], item])).values());
}
uniq(
[
{ id: 1, name: "A" },
{ id: 2, name: "B" },
{ id: 1, name: "A" },
],
"id"
);class实现react setState
class Component {
constructor(initialState = {}) {
this.state = initialState;
this.pendingStates = []; // 存储所有待处理的更新
this.callbacks = []; // 存储所有待执行的回调
this.isBatchingUpdate = false; // 标记是否已安排批量更新
}
// 模拟 setState(支持对象或函数形式的更新)
setState(update, callback) {
this.pendingStates.push(update);
if (callback) {
this.callbacks.push(callback);
}
// 如果还未安排批量更新,则安排一个批量任务
if (!this.isBatchingUpdate) {
this.isBatchingUpdate = true;
// 使用 setTimeout 模拟批量调度:在当前事件循环结束后执行
setTimeout(() => this.flushUpdates(), 0);
}
}
flushUpdates() {
// 依次合并所有 pendingStates 得到最终 state
let nextState = this.state;
this.pendingStates.forEach((update) => {
if (typeof update === "function") {
nextState = { ...nextState, ...update(nextState) };
} else {
nextState = { ...nextState, ...update };
}
});
this.state = nextState;
// 清空 pendingStates 和回调列表
this.pendingStates = [];
// 批量更新完成后,统一执行所有回调
this.callbacks.forEach((cb) => cb(this.state));
this.callbacks = [];
// 重置批量标记
this.isBatchingUpdate = false;
}
}最长的不包含重复字符的子字符串的长度
/**
* 计算输入字符串中最长的不包含重复字符的子字符串的长度。
* 使用滑动窗口和哈希表来记录字符的索引,从而提高效率。
*
* @param {string} ls - 输入字符串
* @returns {number} - 最长的不包含重复字符的子字符串的长度
*/
function lengthOfLongestSubstring(ls: string): number {
// 初始化最大长度为0
let maxLength = 0;
// 初始化滑动窗口的起始位置为0
let start = 0;
// 创建一个哈希表来存储字符及其对应的索引
const charIndexMap: { [key: string]: number } = {};
// 遍历输入字符串
for (let end = 0; end < ls.length; end++) {
// 获取当前字符
const char = ls[end];
// 如果当前字符已经在哈希表中,并且其索引在当前滑动窗口内
if (charIndexMap[char] !== undefined && charIndexMap[char] >= start) {
// 将滑动窗口的起始位置移动到重复字符的下一个位置
start = charIndexMap[char] + 1;
}
// 更新或添加当前字符的索引到哈希表
charIndexMap[char] = end;
// 更新最大长度
maxLength = Math.max(maxLength, end - start + 1);
}
// 返回最大长度
return maxLength;
}indexOf查找
/**
* 计算输入字符串中最长的不包含重复字符的子字符串的长度。
* 使用滑动窗口和字符串操作来记录字符的索引,从而提高效率。
*
* @param {string} ls - 输入字符串
* @returns {number} - 最长的不包含重复字符的子字符串的长度
*/
function lengthOfLongestSubstring(ls: string): number {
// 初始化最大长度为0
let maxLength = 0;
// 初始化当前子字符串为空
let currentSubstring = "";
// 遍历输入字符串
for (let i = 0; i < ls.length; i++) {
const char = ls[i];
const index = currentSubstring.indexOf(char);
// 如果当前字符在当前子字符串中存在
if (index !== -1) {
// 更新最大长度
maxLength = Math.max(maxLength, currentSubstring.length);
// 将当前子字符串截取到重复字符的下一个位置
currentSubstring = currentSubstring.substring(index + 1);
}
// 将当前字符添加到当前子字符串
currentSubstring += char;
}
// 返回最大长度,确保包括最后一个子字符串的长度
return Math.max(maxLength, currentSubstring.length);
}function fn(ls) {
let aw = "";
let i = 0;
for (let j = 0; j < ls.length; j++) {
if (aw.indexOf(ls[j]) > -1) {
i = Math.max(aw.length, i);
aw = "";
} else {
aw += ls[j];
}
}
return i;
}斐波那契数
/**
* 计算第 n 个斐波那契数。
*
* 斐波那契序列是一个由数字组成的系列,其中每个数字是前两个数字的和,通常从 0 和 1 开始。
* 在此函数中,使用迭代方法计算第 n 个斐波那契数,避免了递归调用带来的性能问题。
*
* @param n 斐波那契序列中的位置,从 0 开始。
* @returns 第 n 个斐波那契数。
* @throws {Error} 如果输入为负整数,则抛出错误。
*/
function fibonacci(n: number): number {
// 验证输入以确保其为非负数
if (n < 0) throw new Error("输入必须是非负整数");
// 如果 n 小于等于 1,则直接返回 n,因为结果就是输入本身
if (n <= 1) return n;
// 初始化前两个斐波那契数
let a = 0, b = 1;
// 通过循环计算第 n 个斐波那契数
for (let i = 2; i <= n; i++) {
// 使用解构赋值更新 a 和 b 的值,实现数值的交换与更新
[a, b] = [b, a + b];
}
// 返回计算得到的第 n 个斐波那契数
return b;
}深拷贝函数
/**
* 深拷贝一个给定的对象。
* 深拷贝意味着所有嵌套的对象或数组都会被拷贝,而不仅仅是它们的引用。
* @param obj 需要深拷贝的对象。
* @returns 返回深拷贝后的对象。
*/
function deepClone(obj: any) {
// 检查obj是否是对象或数组,如果不是则直接返回
if (typeof obj !== 'object' || obj === null) {
return obj;
}
// 初始化拷贝的对象,如果原对象是数组则初始化为空数组,否则初始化为空对象
let cObj: any = Array.isArray(obj) ? [] : {};
// 遍历原对象的所有属性
for (let key in obj) {
// 确保只拷贝对象自身的属性,而不是原型链上的属性
if (obj.hasOwnProperty(key)) {
// 递归调用deepClone,深拷贝每个属性值
cObj[key] = deepClone(obj[key]);
}
}
// 返回深拷贝后的对象
return cObj;
}快速排序
/**
* 快速排序算法的默认实现
*
* 此函数使用分治法对数组进行排序,通过递归方式将数组分为较小的部分并进行排序
* 它选取一个基准值,然后将数组分为两部分:一部分包含小于基准值的元素,另一部分包含大于基准值的元素
* 这个过程一直重复,直到整个数组变得有序
*
* @param arr 要排序的数组
* @param left 排序开始的索引,默认为数组的起始位置
* @param right 排序结束的索引,默认为数组的结束位置
*/
function quickSort(arr: number[], left: number = 0, right: number) {
// 检查递归的终止条件,如果左指针大于右指针,则终止递归
if (left > right) return;
// 选取基准值,这里选择数组最左边的元素作为基准
let base = arr[left],
i = left,
j = right;
// 开始寻找基准值的正确位置,直到i和j相遇
while (i != j) {
// 从右向左找到第一个小于基准值的元素
while (arr[j] >= base && i < j) {
j--;
}
// 从左向右找到第一个大于基准值的元素
while (arr[i] <= base && i < j) {
i++;
}
// 如果找到的两个元素不满足条件,则交换它们的位置
[arr[i], arr[j]] = [arr[j], arr[i]];
}
// 将基准值放到正确的位置上
arr[left] = arr[i];
arr[i] = base;
// 递归对基准值左边的数组进行排序
quickSort(arr, left, i - 1);
// 递归对基准值右边的数组进行排序
quickSort(arr, i + 1, right);
}字符串中频率最高的字符
/**
* 找出字符串中出现频率最高的字符
* @param ls 输入的字符串
* @returns 出现频率最高的字符
*/
function findMostFrequentChar(ls: string) {
// 创建一个哈希表来记录每个字符的出现次数
let hash: { [x: string]: number } = {}
// 初始化最大出现次数为0
let maxCount = 0;
// 初始化出现频率最高的字符为空字符串
let mostFrequentChar = ''
// 遍历字符串中的每个字符
for (const i of ls) {
// 在哈希表中更新字符的出现次数,如果字符不存在则初始化为0后加1
hash[i] = (hash[i] || 0) + 1;
// 如果当前字符的出现次数超过了最大出现次数
if (hash[i] > maxCount) {
// 更新出现频率最高的字符为当前字符
mostFrequentChar = i
// 更新最大出现次数为当前字符的出现次数
maxCount = hash[i]
}
}
// 返回出现频率最高的字符
return mostFrequentChar;
}逆波兰表达式
function evalRPN(tokens) {
// 定义一个栈用于存储操作数
const stack = [];
// 定义运算符及其对应的计算方法
const operators = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => Math.trunc(a / b)
};
// 遍历输入的 token 数组
for (const token of tokens) {
// 如果 token 是运算符,则弹出两个操作数进行计算
if (operators[token]) {
const b = stack.pop(); // 取出栈顶元素作为右操作数
const a = stack.pop(); // 取出次栈顶元素作为左操作数
stack.push(operators[token](a, b)); // 计算结果并压入栈中
} else {
// 如果 token 是数字,则转换为数字类型并压入栈中
stack.push(Number(token));
}
}
// 返回栈顶元素,即最终计算结果
return stack[0];
}
// 示例用法
const tokens = ["4", "13", "5", "/", "+"];
console.log(evalRPN(tokens)); // 输出 6
一些实用的小方法
https://blog.fullsize.cn/2025/02/08/notion/yi-xie-shi-yong-de-xiao-fang-fa/