1. 数据类型
判断
JavaScript
的数据类型,包含基本类型、引用类型以及自定义的类。
1.1 核心代码
function getDataType(data) {
// 处理 null 的特殊情况
if (data=== null) return 'null'
// 处理基本类型(除 null 外)和函数
const baseType = typeof data
if (baseType !== 'object') {
// 处理 NaN 的特殊情况
if (Number.isNaN(data)) return 'nan'
return baseType
}
// 通过 Object.prototype.toString 获取详细类型
const detailType = Object.prototype.toString.call(data)
const typeName = detailType.slice(8, -1).toLowerCase()
// 处理包装对象的情况(如 new Number(123))
if (typeName === 'object') {
const constructorName = data.constructor?.name?.toLowerCase()
if (constructorName && constructorName !== 'object') {
return constructorName
}
}
return typeName
}
// 测试用例
console.log(getDataType(null)) // 'null'
console.log(getDataType(undefined)) // 'undefined'
console.log(getDataType(true)) // 'boolean'
console.log(getDataType(42)) // 'number'
console.log(getDataType(NaN)) // 'nan'
console.log(getDataType('hello')) // 'string'
console.log(getDataType(Symbol())) // 'symbol'
console.log(getDataType(10n)) // 'bigint'
console.log(getDataType({})) // 'object'
console.log(getDataType([])) // 'array'
console.log(getDataType(/regex/)) // 'regexp'
console.log(getDataType(new Date())) // 'date'
console.log(getDataType(() => {})) // 'function'
console.log(getDataType(new Number(1))) // 'number'
console.log(getDataType(new String('')))// 'string'
console.log(getDataType(Math)) // 'math'
console.log(getDataType(JSON)) // 'json'
1.2 代码解析
功能特性:
- 完整支持所有
JavaScript
内置类型 - 特殊处理情况:
- 精确识别
null
- 单独处理
NaN
- 区分包装对象和原始值
- 识别内置对象类型(如
Date
、RegExp
等)
- 精确识别
- 返回统一的小写类型字符串
实现原理:
- 优先处理
null
的特殊情况 - 使用
typeof
处理基本类型(除null
) - 通过
Object.prototype.toString
识别对象子类型 - 处理包装对象的构造函数名称
- 单独处理
NaN
的特殊情况 - 方法返回的可能类型包括:
- ‘null’
- ‘undefined’
- ‘boolean’
- ‘number’
- ‘nan’
- ‘string’
- ‘symbol’
- ‘bigint’
- ‘array’
- ‘object’
- ‘function’
- ‘regexp’
- ‘date’
- ‘math’
- ‘json’
- 其他内置对象的类型名称(如 ‘map’、‘set’ 等)
2. 解析路径
支持绝对路径和相对路径的解析,并兼容浏览器和
Node.js
环境。
2.1 核心代码
/**
* 解析 URL 地址
* @param {string} url - 要解析的 URL 字符串
* @param {string} [base] - 可选的基础 URL(用于解析相对路径)
* @returns {object} 包含解析后信息的对象
*/
function parseUrl(url, base) {
// 自动处理浏览器环境的基础 URL
if (typeof base === 'undefined' && typeof window !== 'undefined') {
base = window.location.href;
}
try {
// 创建 URL 对象
const parsed = new URL(url, base || 'http://127.0.0.1');
// 解析查询参数
const queryParams = {};
parsed.searchParams.forEach((value, key) => {
queryParams[key] = decodeURIComponent(value);
});
return {
href: decodeURIComponent(parsed.href),
protocol: parsed.protocol.replace(':', ''),
hostname: parsed.hostname,
port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
path: parsed.pathname,
query: decodeURIComponent(parsed.search),
queryParams: queryParams,
hash: parsed.hash.replace('#', ''),
isAbsolute: /^[a-z][a-z0-9+.-]*:/.test(url),
origin: parsed.origin,
auth: parsed.username || parsed.password
? `${parsed.username}:${parsed.password}`
: null
};
} catch (error) {
console.error('Invalid URL:', error.message);
return null;
}
}
// 使用示例
console.log(parseUrl('https://developer.mozilla.org/zh-CN/search?q=URL'))
console.log(parseUrl('../path/../to/file?query=1', 'https://developer.mozilla.org/dir/sub'))
console.log(parseUrl('//developer.mozilla.org/zh-CN/docs/Learn'))
console.log(parseUrl('/images/logo.png'))
console.log(parseUrl('?query=test'))
console.log(parseUrl('#anchor'))
2.2 代码解析
功能特性:
- 完整解析:支持解析协议、认证信息、域名、端口、路径、查询参数和哈希
- 智能处理,支持:
- 自动识别绝对/相对
URL
- 自动解码
URL
编码字符(如中文) - 自动处理默认端口(
HTTP=80, HTTPS=443
)
- 自动识别绝对/相对
- 兼容性,支持:
- 浏览器和
Node
环境 - 正确处理相对路径(需提供
base
参数)
- 浏览器和
- 错误处理:对非法
URL
返回null
并打印错误信息 - 兼容中文等特殊字符编解码
返回值解析:
属性 | 类型 | 说明 |
---|---|---|
href | string | 完整 URL |
protocol | string | 协议(不含冒号) |
hostname | string | 域名 |
port | number | 端口号 |
path | string | 路径部分 |
query | string | 完整查询字符串(含问号) |
queryParams | object | 解析后的查询参数对象 |
hash | string | 哈希值(不含井号) |
isAbsolute | boolean | 是否为绝对 URL |
origin | string | 协议+域名+端口 |
auth | string | 认证信息(username:password) |
3. 颜色转换
十六进制的颜色值转
rgba
颜色字符串。
3.1 核心代码
/**
* 将十六进制颜色值转换为RGBA格式
* @param {string} hex - 十六进制颜色值(支持 #RGB、#RRGGBB 格式)
* @param {number} alpha - 透明度(0-1之间的数值)
* @returns {string} rgba颜色字符串
*/
function hexToRGBA(hex, alpha = 1) {
// 移除 # 号并验证格式
let hexValue = hex.replace(/^#/, '');
// 有效性验证
if (!/^([0-9A-F]{3}){1,2}$/i.test(hexValue)) {
throw new Error('Invalid hexadecimal color value');
}
// 处理简写格式(如 #RGB)
if (hexValue.length === 3) {
hexValue = hexValue.split('').map(c => c + c).join('');
}
// 解析颜色分量
const r = parseInt(hexValue.substring(0, 2), 16);
const g = parseInt(hexValue.substring(2, 4), 16);
const b = parseInt(hexValue.substring(4, 6), 16);
// 处理透明度范围
const a = Math.min(1, Math.max(0, Number(alpha)));
return `rgba(${r}, ${g}, ${b}, ${a.toFixed(4).replace(/\.?0+$/, '')})`;
}
// 使用示例
console.log(hexToRGBA('#f00', 0.5)); // rgba(255, 0, 0, 0.5)
console.log(hexToRGBA('#00ff00', 1)); // rgba(0, 255, 0, 1)
console.log(hexToRGBA('abc', 0.75)); // rgba(170, 187, 204, 0.75)
console.log(hexToRGBA('#336699', 1.5)); // rgba(51, 102, 153, 1)
console.log(hexToRGBA('#a1b2c3', -0.1)); // rgba(161, 178, 195, 0)
3.2 代码解析
功能特性:
- 格式支持:
- 支持
#RGB
简写格式 - 支持
#RRGGBB
完整格式 - 支持不带
#
号的输入
- 支持
- 有效性验证:
- 自动检测非法十六进制颜色值
- 抛出可识别的错误信息
- 透明度处理:
- 自动限制透明度在
0-1
之间 - 支持数字类型输入
- 智能处理小数精度
- 自动限制透明度在
- 输出优化:
- 自动去除多余的小数位(如
1.0000 → 1
) - 保留必要精度(如
0.1234 → 0.1234
)
- 自动去除多余的小数位(如
3.3 异常处理
try {
hexToRGBA('#zzz', 0.5)
} catch (e) {
console.error(e.message) // 输出:Invalid hexadecimal color value
}
4. 数据深拷贝
深度拷贝
JavaScript
的数据类型。
4.1 核心代码
function deepClone(target, map = new WeakMap()) {
// 处理基本类型和函数
if (typeof target !== 'object' || target === null) return target
// 处理循环引用
if (map.has(target)) return map.get(target)
// 处理特殊对象类型
const constructor = target.constructor
if (/^(Date|RegExp)$/i.test(constructor.name)) {
return new constructor(target)
}
// 初始化拷贝对象
const clone = Array.isArray(target) ? [] : {}
// 记录已拷贝对象
map.set(target, clone)
// 处理Symbol作为key的情况
const symbolKeys = Object.getOwnPropertySymbols(target)
if (symbolKeys.length) {
symbolKeys.forEach(symKey => {
clone[symKey] = deepClone(target[symKey], map)
})
}
// 递归拷贝属性
for (const key in target) {
if (target.hasOwnProperty(key)) {
clone[key] = deepClone(target[key], map)
}
}
return clone
}
4.2 代码解析
功能特性:
- 支持数据类型:
- 基本类型(
Number/String/Boolean
等) - 普通对象/数组
Date/RegExp
对象- 循环引用
Symbol
作为对象键
- 基本类型(
- 解决循环引用:
- 使用
WeakMap
记录已拷贝对象,避免无限递归
- 使用
- 保持原型链:
- 自动限制透明度在
0-1
之间 - 支持数字类型输入
- 智能处理小数精度
- 自动限制透明度在
- 输出优化:
- 通过
target.constructor
创建正确类型的对象
- 通过
方案对比:
方法 | 优点 | 缺点 |
---|---|---|
JSON方法 | 简单快速 | 丢失函数/Symbol/特殊对象 |
递归实现 | 支持更多类型 | 需自行处理特殊对象和循环引用 |
structuredClone | 浏览器原生支持 | 不支持函数/无法克隆DOM节点 |
Lodash.cloneDeep | 功能最完整 | 需引入第三方库 |
本实现 | 平衡功能与代码体积 | 不处理Map/Set等ES6+数据结构 |
5. 数据深度合并
将两个复杂的对象,合并成单个对象。
5.1 核心代码
function deepMerge(target, source, map = new WeakMap()) {
// 处理非对象类型或循环引用
if (typeof source !== 'object' || source === null) return source;
if (map.has(source)) return map.get(source);
// 处理特殊对象类型(如Date/RegExp)
const constructor = source.constructor;
if (constructor === Date || constructor === RegExp) {
return new constructor(source);
}
// 初始化合并容器
const output = Array.isArray(source) ? [...source] : { ...target };
map.set(source, output);
// 递归合并逻辑
Object.keys(source).forEach(key => {
const sourceVal = source[key];
const targetVal = target?.[key];
if (typeof sourceVal === 'object' && sourceVal !== null) {
output[key] = deepMerge(targetVal || {}, sourceVal, map);
} else if (Array.isArray(sourceVal)) {
output[key] = Array.isArray(targetVal)
? [...targetVal, ...sourceVal]
: [...sourceVal];
} else {
output[key] = sourceVal;
}
});
// 处理Symbol键
Object.getOwnPropertySymbols(source).forEach(sym => {
output[sym] = source[sym];
});
return output;
}
5.2 代码解析
功能特性:
- 合并策略:
- 基础类型:源对象属性直接覆盖目标对象
- 嵌套对象:递归合并保留双方属性,如
{a:1}
合并{b:2}
→{a:1,b:2}
- 数组处理:默认采用追加模式(
[1].concat([2]
),可通过修改逻辑实现覆盖
- 特殊类型支持:
- 自动处理
Date/RegExp
等对象的独立拷贝 - 支持
Symbol
作为对象键的合并
- 自动处理
- 防御性设计:
- 使用
WeakMap
防止循环引用导致的无限递归 - 通过对象展开符
...
确保原始对象不被修改
- 使用
方案对比:
方法 | 优点 | 缺点 |
---|---|---|
JSON序列化 | 简单快速 | 丢失函数/Symbol/原型链 |
Lodash.mergeWith | 功能最完整 | 需引入第三方库 |
扩展运算符 | 语法简洁 | 仅支持一级浅合并 |
本实现 | 支持递归合并和特殊类型 | 需自行处理Map/Set等类型 |
扩展建议:
- 数组覆盖模式:
- 将数组处理逻辑改为
output[key] = [...sourceVal]
实现完全覆盖
- 将数组处理逻辑改为
- 混合合并策略:
- 可添加回调函数参数,允许自定义不同类型属性的合并规则
- 防御性设计:
- 使用
Lodash
的_.mergeWith()
实现更复杂的合并逻辑
- 使用
6. 数据精度
用于处理
JavaScript
的数据精度问题。
6.1 核心代码
function getDecimalLength(num) {
const str = String(num);
const index = str.indexOf('.');
const expIndex = str.indexOf('e-');
if (expIndex > 0) { // 处理科学计数法
const exp = parseInt(str.slice(expIndex + 2));
return (index > 0 ? str.slice(index + 1, expIndex).length : 0) + exp;
}
return index > 0 ? str.slice(index + 1).length : 0;
}
function toInt(num, len) {
return +num.toString().replace('.', '').padEnd(len + (num.toString().split('.')[0] || '').length, '0');
}
const precision = {
add: (a, b) => {
const maxLen = Math.max(getDecimalLength(a), getDecimalLength(b));
const base = 10 ** maxLen;
return (precision.mul(a, base) + precision.mul(b, base)) / base;
},
sub: (a, b) => precision.add(a, -b),
mul: (a, b) => {
const len1 = getDecimalLength(a);
const len2 = getDecimalLength(b);
const base = 10 ** (len1 + len2);
return (toInt(a, len2) * toInt(b, len1)) / base;
},
div: (a, b) => {
const len1 = getDecimalLength(a);
const len2 = getDecimalLength(b);
const base = 10 ** (len2 - len1);
return (toInt(a, len2) / toInt(b, len1)) * base;
}
};
6.2 代码解析
功能特性:
- 处理科学计数法表达式
- 处理字符串数值表达式
扩展建议:
- 精度限制:
Number.MAX_SAFE_INTEGER
,超出范围抛出异常 - 非数字以及非字符串数字:需要处理
NaN
等情况
7. 时间格式化
给定合法时间和格式,将其格式化成对应的数据格式。
7.1 核心代码
function formatDate(date = new Date(), format = 'YYYY-MM-DD HH:mm:ss') {
const d = date instanceof Date ? date : new Date(date);
const pad = (n) => String(n).padStart(2, '0');
const time = {
YYYY: d.getFullYear(),
MM: pad(d.getMonth() + 1),
DD: pad(d.getDate()),
HH: pad(d.getHours()),
hh: pad(d.getHours() % 12 || 12),
mm: pad(d.getMinutes()),
ss: pad(d.getSeconds()),
A: d.getHours() < 12 ? 'AM' : 'PM',
a: d.getHours() < 12 ? 'am' : 'pm'
};
return format.replace(
/YYYY|MM|DD|HH|hh|mm|ss|A|a/g,
match => time[match]
);
}
7.2 代码解析
功能特性:
- 支持动态格式配置
- 自动处理12/24小时制转换
- 严格区分大小写(如MM与mm)
- 保持原Date对象引用关系
- 时间复杂度O(n),n为格式字符串长度
扩展建议:
- 支持毫秒级格式化
- 处理无效日期返回值
- 处理时区转换
8. 扁平结构树数据格式化
将扁平化的树数据格式化成树结构数据。
8.1 核心代码
function formatFlattenTreeData(nodes, id = 'id', pId = 'pId') {
const map = new Map();
const roots = [];
const orphanNodes = []; // 新增孤儿节点收集,即 pId 在 nodes 中找不到对应的 id
// 浅拷贝避免污染原数据
const copy = nodes.map(n => ({ ...n, children: [] }));
copy.forEach(node => map.set(node[id], node));
copy.forEach(node => {
const parentId = node[pId];
if (parentId != null) {
map.has(parentId)
? map.get(parentId).children.push(node)
: orphanNodes.push(node); // 明确处理异常数据
} else {
roots.push(node);
}
});
if (orphanNodes.length > 0) {
console.warn(`Orphan nodes detected: ${orphanNodes.length}`);
}
// 可选项:将孤儿节点作为根节点返回
return roots.concat(orphanNodes);
}
8.2 代码解析
功能特性:
- 高效构建:利用Map实现O(1)查找,两次O(n)遍历完成树构建,时间复杂度O(n)最优
- 逻辑清晰:分初始化、建立索引、构建父子关系三阶段,代码易读
- 多根支持:正确收集
parentId == null
的节点作为根节点集合 - 浅拷贝避免污染原数据