52个JavaScript常用工具函数整理
本文整理了大量实用的JavaScript工具函数,涵盖类型判断、数学运算、字符串处理、数组操作、对象处理、日期处理、浏览器操作等核心功能。主要包括:类型检测(如isArray、isPlainObject)、数学计算(精确加减乘除)、字符串转换(驼峰/下划线命名)、数组操作(去重/分块/排序)、对象处理(深拷贝/合并)、日期格式化、DOM操作、网络请求封装等。这些函数经过优化可直接使用,能显著提升开
1、isStatic: 检测数据是不是除了symbol外的原始数据。
function isStatic(value) {return (typeof value === 'string' ||typeof value === 'number' ||typeof value === 'boolean' ||typeof value === 'undefined' ||value === null)}
2、isPrimitive:检测数据是不是原始数据
function isPrimitive(value) {return isStatic(value) || typeof value === 'symbol'}
3、isObject:判断数据是不是引用类型的数据(例如:array,function,object,regexe,new Number(),new String())
function isObject(value) {let type = typeof value;return value != null && (type == 'object' || type == 'function');}
4、isObjectLike:检查value是否是类对象。如果一个值是类对象,那么它不应该是null,而且typeof后的结果是“object”。
function isObjectLike(value) {return value != null && typeof value == 'object';}
5、getRawType:获取数据类型,返回结果为Number、String、Object、Array等。
function getRawType(value) {return Object.prototype.toString.call(value).slice(8, -1)}// getoRawType([]) ⇒ Array
6、isPlainObject:判断数据是不是Object类型的数据。
function isPlainObject(obj) {return Object.prototype.toString.call(obj) === '[object Object]'}
7、isArray:判断数据是不是数组类型的数据(Array.isArray的兼容写法)
function isArray(arr) {return Object.prototype.toString.call(arr) === '[object Array]'}// 将isArray挂载到Array上Array.isArray = Array.isArray || isArray;
8、isRegExp:判断数据是不是正则对象
function isRegExp(value) {return Object.prototype.toString.call(value) === '[object RegExp]'}
9、isDate:判断数据是不是时间对象
function isDate(value) {return Object.prototype.toString.call(value) === '[object Date]'}
10、isNative:判断value是不是浏览器内置函数
内置函数toString后的主体代码块为[native code] ,而非内置函数则为相关代码,所以非内置函数可以进行拷贝(toString后掐头去尾再由Function转)
function isNative(value) {return typeof value === 'function' && /native code/.test(value.toString())}
11、isFunction:检查value是不是函数
function isFunction(value) {return Object.prototype.toString.call(value) === '[object Function]'}
12、isLength:检查value是否为有效的类数组长度
function isLength(value) {return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= Number.MAX_SAFE_INTEGER;}
13、isArrayLike:检查value是否是类数组
如果一个值被认为是类数组,那么它不是一个函数,并且value.length是个整数,大于等于0,小于或等于Number.MAX_SAFE_INTEGER。这里字符串也被当作类数组。
function isArrayLike(value) {return value != null && isLength(value.length) && !isFunction(value);}
14、isEmpty:检查value是否为空
如果是null,直接返回true;如果是类数组,判断数据长度;如果是Object对象,判断是否具有属性;如果是其他数据,直接返回false(也可以改为返回true)
function isEmpty(value) {if (value == null) {return true;}if (isArrayLike(value)) {return !value.length;} else if (isPlainObject(value)) {for (let key in value) {if (hasOwnProperty.call(value, key)) {return false;}}}return false;}
15、cached:记忆函数:缓存函数的运算结果
function cached(fn) {let cache = Object.create(null);return function cachedFn(str) {let hit = cache[str];return hit || (cache[str] = fn(str))}}
16、camelize:横线转驼峰命名
let camelizeRE = /-(\w)/g;function camelize(str) {return str.replace(camelizeRE, function(_, c) {return c ? c.toUpperCase() : '';})}//ab-cd-ef ==> abCdEf//使用记忆函数let _camelize = cached(camelize)
17、hyphenate:驼峰命名转横线命名:拆分字符串,使用-相连,并且转换为小写
let hyphenateRE = /\B([A-Z])/g;function hyphenate(str){return str.replace(hyphenateRE, '-$1').toLowerCase()}//abCd ==> ab-cd//使用记忆函数let _hyphenate = cached(hyphenate);
18、capitalize:字符串首位大写
function capitalize(str) {return str.charAt(0).toUpperCase() + str.slice(1)}// abc ==> Abc//使用记忆函数let _capitalize = cached(capitalize)
19、extend:将属性混合到目标对象中
function extend(to, _form) {for(let key in _form) {to[key] = _form[key];}return to}
20、Object.assign:对象属性复制,浅拷贝
Object.assign = Object.assign || function() {if (arguments.length == 0) throw new TypeError('Cannot convert undefined or null to object');let target = arguments[0],args = Array.prototype.slice.call(arguments, 1),key;args.forEach(function(item) {for (key in item) {item.hasOwnProperty(key) && (target[key] = item[key])}})return target}
使用Object.assign可以浅克隆一个对象:
let clone = Object.assign({}, target);
简单的深克隆可以使用jsON.parse()和jsON.stringify(),这两个api是解析json数据的,所以只能解析除symbol外的原始类型及数组和对象。
let clone = JSON.parse( JSON.stringify(target) )
21、clone:克隆数据,可深度克隆
这里列出了原始类型,时间、正则、错误、数组、对象的克隆规则,其他的可自行补充。
function clone(value, deep) {if (isPrimitive(value)) {return value}if (isArrayLike(value)) { //是类数组value = Array.prototype.slice.call(vall)return value.map(item => deep ? clone(item, deep) : item)} else if (isPlainObject(value)) { //是对象let target = {}, key;for (key in value) {value.hasOwnProperty(key) && ( target[key] = deep ? clone(value[key], value[key] ))}}let type = getRawType(value);switch(type) {case 'Date':case 'RegExp':case 'Error': value = new window[type](value); break;}return value}
22、识别各种浏览器及平台
//运行环境是浏览器let inBrowser = typeof window !== 'undefined';//运行环境是微信let inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform;let weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();//浏览器 UA 判断let UA = inBrowser && window.navigator.userAgent.toLowerCase();let isIE = UA && /msie|trident/.test(UA);let isIE9 = UA && UA.indexOf('msie 9.0') > 0;let isEdge = UA && UA.indexOf('edge/') > 0;let isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android');let isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios');let isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
23、getExplorerInfo:获取浏览器信息
function getExplorerInfo() {let t = navigator.userAgent.toLowerCase();return 0 <= t.indexOf("msie") ? { //ie < 11type: "IE",version: Number(t.match(/msie ([\d]+)/)[1])} : !!t.match(/trident\/.+?rv:(([\d.]+))/) ? { // ie 11type: "IE",version: 11} : 0 <= t.indexOf("edge") ? {type: "Edge",version: Number(t.match(/edge\/([\d]+)/)[1])} : 0 <= t.indexOf("firefox") ? {type: "Firefox",version: Number(t.match(/firefox\/([\d]+)/)[1])} : 0 <= t.indexOf("chrome") ? {type: "Chrome",version: Number(t.match(/chrome\/([\d]+)/)[1])} : 0 <= t.indexOf("opera") ? {type: "Opera",version: Number(t.match(/opera.([\d]+)/)[1])} : 0 <= t.indexOf("Safari") ? {type: "Safari",version: Number(t.match(/version\/([\d]+)/)[1])} : {type: t,version: -1}}
24、isPCBroswer:检测是否为PC端浏览器模式
function isPCBroswer() {let e = navigator.userAgent.toLowerCase(), t = "ipad" == e.match(/ipad/i), i = "iphone" == e.match(/iphone/i), r = "midp" == e.match(/midp/i), n = "rv:1.2.3.4" == e.match(/rv:1.2.3.4/i), a = "ucweb" == e.match(/ucweb/i), o = "android" == e.match(/android/i), s = "windows ce" == e.match(/windows ce/i), l = "windows mobile" == e.match(/windows mobile/i);return !(t || i || r || n || a || o || s || l)}
25、unique: 数组去重,返回一个新数组
function unique(arr){if(!isArrayLink(arr)){ //不是类数组对象return arr}let result = []let objarr = []let obj = Object.create(null)arr.forEach(item => {if(isStatic(item)){//是除了symbol外的原始数据let key = item + '_' + getRawType(item);if(!obj[key]){obj[key] = trueresult.push(item)}}else{//引用类型及symbolif(!objarr.includes(item)){objarr.push(item)result.push(item)}}})return resulte}
26、Set简单实现
window.Set = window.Set || (function () {function Set(arr) {this.items = arr ? unique(arr) : [];this.size = this.items.length; // Array的大小}Set.prototype = {add: function (value) {// 添加元素,若元素已存在,则跳过,返回 Set 结构本身。if (!this.has(value)) {this.items.push(value);this.size++;}return this;},clear: function () {//清除所有成员,没有返回值。this.items = []this.size = 0},delete: function (value) {//删除某个值,返回一个布尔值,表示删除是否成功。return this.items.some((v, i) => {if(v === value){this.items.splice(i,1)return true}return false})},has: function (value) {//返回一个布尔值,表示该值是否为Set的成员。return this.items.some(v => v === value)},values: function () {return this.items},}return Set;}());
27、repeat:生成一个重复的字符串,有n个str组成,可修改为填充为数组等
function repeat(str, n) {let res = '';while(n) {if(n % 2 === 1) {res += str;}if(n > 1) {str += str;}n >>= 1;}return res};//repeat('123',3) ==> 123123123
28、dateFormater:格式化时间
function dateFormater(formater, t){let date = t ? new Date(t) : new Date(),Y = date.getFullYear() + '',M = date.getMonth() + 1,D = date.getDate(),H = date.getHours(),m = date.getMinutes(),s = date.getSeconds();return formater.replace(/YYYY|yyyy/g,Y).replace(/YY|yy/g,Y.substr(2,2)).replace(/MM/g,(M<10?'0':'') + M).replace(/DD/g,(D<10?'0':'') + D).replace(/HH|hh/g,(H<10?'0':'') + H).replace(/mm/g,(m<10?'0':'') + m).replace(/ss/g,(s<10?'0':'') + s)}// dateFormater('YYYY-MM-DD HH:mm', t) ==> 2019-06-26 18:30// dateFormater('YYYYMMDDHHmm', t) ==> 201906261830
29、dateStrForma:将指定字符串由一种时间格式转化为另一种。From的格式应对应str的位置
function dateStrForma(str, from, to){//'20190626' 'YYYYMMDD' 'YYYY年MM月DD日'str += ''let Y = ''if(~(Y = from.indexOf('YYYY'))){Y = str.substr(Y, 4)to = to.replace(/YYYY|yyyy/g,Y)}else if(~(Y = from.indexOf('YY'))){Y = str.substr(Y, 2)to = to.replace(/YY|yy/g,Y)}let k,i['M','D','H','h','m','s'].forEach(s =>{i = from.indexOf(s+s)k = ~i ? str.substr(i, 2) : ''to = to.replace(s+s, k)})return to}// dateStrForma('20190626', 'YYYYMMDD', 'YYYY年MM月DD日') ==> 2019年06月26日// dateStrForma('121220190626', '----YYYYMMDD', 'YYYY年MM月DD日') ==> 2019年06月26日// dateStrForma('2019年06月26日', 'YYYY年MM月DD日', 'YYYYMMDD') ==> 20190626// 一般的也可以使用正则来实现//'2019年06月26日'.replace(/(\d{4})年(\d{2})月(\d{2})日/, '$1-$2-$3') ==> 2019-06-26
30、getPropByPath:根据字符串路径获取对象属性:‘obj[0].count’
function getPropByPath(obj, path, strict) {let tempObj = obj;path = path.replace(/\[(\w+)\]/g, '.$1'); //将[0]转化为.0path = path.replace(/^\./, ''); //去除开头的.let keyArr = path.split('.'); //根据.切割let i = 0;for (let len = keyArr.length; i < len - 1; ++i) {if (!tempObj && !strict) break;let key = keyArr[i];if (key in tempObj) {tempObj = tempObj[key];} else {if (strict) {//开启严格模式,没找到对应key值,抛出错误throw new Error('please transfer a valid prop path to form item!');}break;}}return {o: tempObj, //原始数据k: keyArr[i], //key值v: tempObj ? tempObj[keyArr[i]] : null // key值对应的值};};
31、GetUrlParam:获取Url参数,返回一个对象
function GetUrlParam(){let url = document.location.toString();let arrObj = url.split("?");let params = Object.create(null)if (arrObj.length > 1){arrObj = arrObj[1].split("&");arrObj.forEach(item=>{item = item.split("=");params[item[0]] = item[1]})}return params;}// ?a=1&b=2&c=3 ==> {a: "1", b: "2", c: "3"}
32、downloadFile:base64数据导出文件,文件下载
function downloadFile(filename, data) {let DownloadLink = document.createElement('a');if (DownloadLink) {document.body.appendChild(DownloadLink);DownloadLink.style = 'display: none';DownloadLink.download = filename;DownloadLink.href = data;if (document.createEvent) {let DownloadEvt = document.createEvent('MouseEvents');DownloadEvt.initEvent('click', true, false);DownloadLink.dispatchEvent(DownloadEvt);} else if (document.createEventObject) {DownloadLink.fireEvent('onclick');} else if (typeof DownloadLink.onclick == 'function') {DownloadLink.onclick();}document.body.removeChild(DownloadLink);}}
33、toFullScreen:全屏
function toFullScreen() {let elem = document.body;elem.webkitRequestFullScreen? elem.webkitRequestFullScreen(): elem.mozRequestFullScreen? elem.mozRequestFullScreen(): elem.msRequestFullscreen? elem.msRequestFullscreen(): elem.requestFullScreen? elem.requestFullScreen(): alert("浏览器不支持全屏");}
34、exitFullscreen:退出全屏
function exitFullscreen() {let elem = parent.document;elem.webkitCancelFullScreen? elem.webkitCancelFullScreen(): elem.mozCancelFullScreen? elem.mozCancelFullScreen(): elem.cancelFullScreen? elem.cancelFullScreen(): elem.msExitFullscreen? elem.msExitFullscreen(): elem.exitFullscreen? elem.exitFullscreen(): alert("切换失败,可尝试Esc退出");}
35、requestAnimationFrame:window动画
window.requestAnimationFrame = window.requestAnimationFrame ||window.webkitRequestAnimationFrame ||window.mozRequestAnimationFrame ||window.msRequestAnimationFrame ||window.oRequestAnimationFrame ||function (callback) {//为了使setTimteout的尽可能的接近每秒60帧的效果window.setTimeout(callback, 1000 / 60);}window.cancelAnimationFrame = window.cancelAnimationFrame ||window.webkitCancelAnimationFrame ||window.mozCancelAnimationFrame ||window.msCancelAnimationFrame ||window.oCancelAnimationFrame ||function (id) {//为了使setTimteout的尽可能的接近每秒60帧的效果window.clearTimeout(id);}
36、_isNaN:检查数据是否是非数字值
function _isNaN(v){return !(typeof v === 'string' || typeof v === 'number') || isNaN(v)}
37、max:求取数组中非NaN数据中的最大值
function max(arr){arr = arr.filter(item => !_isNaN(item))return arr.length ? Math.max.apply(null, arr) : undefined}//max([1, 2, '11', null, 'fdf', []]) ==> 11
38、min:求取数组中非NaN数据中的最小值
function min(arr){arr = arr.filter(item => !_isNaN(item))return arr.length ? Math.min.apply(null, arr) : undefined}//min([1, 2, '11', null, 'fdf', []]) ==> 1
39、random:返回一个lower-upper直接的随机数。(lower、upper无论正负与大小,但必须是非NaN的数据)
function random(lower, upper) {lower = +lower || 0upper = +upper || 0return Math.random() * (upper - lower) + lower;}//random(0, 0.5) ==> 0.3567039135734613//random(2, 1) ===> 1.6718418553475423//random(-2, -1) ==> -1.4474325452361945
40、Object.keys:返回一个由一个给定对象的自身可枚举属性组成的数组
Object.keys = Object.keys || function keys(object) {if (object === null || object === undefined) {throw new TypeError('Cannot convert undefined or null to object');}let result = [];if (isArrayLike(object) || isPlainObject(object)) {for (let key in object) {object.hasOwnProperty(key) && (result.push(key))}}return result;}
41、Object.values:返回一个给定对象自身的所有可枚举属性值的数组
Object.values = Object.values || function values(object) {if (object === null || object === undefined) {throw new TypeError('Cannot convert undefined or null to object');}let result = [];if (isArrayLike(object) || isPlainObject(object)) {for (let key in object) {object.hasOwnProperty(key) && (result.push(object[key]))}}return result;}
42、arr.fill:使用value值填充array,从start位置开始,到end位置结束(但不包含end位置),返回原数组。
Array.prototype.fill = Array.prototype.fill || function fill(value, start, end) {let ctx = thislet length = ctx.length;start = parseInt(start)if(isNaN(start)){start = 0}else if (start < 0) {start = -start > length ? 0 : (length + start);}end = parseInt(end)if(isNaN(end) || end > length){end = length}else if (end < 0) {end += length;}while (start < end) {ctx[start++] = value;}return ctx;}//Array(3).fill(2) ===> [2, 2, 2]
43、arr.includes:用来判断一个数组是否包含一个指定的值,如果是返回true,否则返回false,可指定开始查询的位置。
Array.prototype.includes = Array.prototype.includes || function includes(value, start) {let ctx = this;let length = ctx.length;start = parseInt(start)if(isNaN(start)) {start = 0} else if (start < 0) {start = -start > length ? 0 : (length + start);}let index = ctx.indexOf(value);return index >= start;}
44、返回数组中通过测试(函数fn内判断)的第一个元素的值。
Array.prototype.find = Array.prototype.find || function find(fn, ctx) {ctx = ctx || this;let result;ctx.some((value, index, arr), thisValue) => {return fn(value, index, arr) ? (result = value, true) : false})return result}
45、arr.findIndex:返回数组中通过测试(函数fn内判断)的第一个元素的下标
Array.prototype.findIndex = Array.prototype.findIndex || function findIndex(fn, ctx){ctx = ctx || thislet result;ctx.some((value, index, arr), thisValue) => {return fn(value, index, arr) ? (result = index, true) : false})return result}
46、performance.timing:利用performance.timing进行性能分析。
window.onload = function() {setTimeout(function() {let t = performance.timing;console.log('DNS查询耗时 :' + (t.domainLookupEnd - t.domainLookupStart).toFixed(0))console.log('TCP链接耗时 :' + (t.connectEnd - t.connectStart).toFixed(0))console.log('request请求耗时 :' + (t.responseEnd - t.responseStart).toFixed(0))console.log('解析dom树耗时 :' + (t.domComplete - t.domInteractive).toFixed(0))console.log('白屏时间 :' + (t.responseStart - t.navigationStart).toFixed(0))console.log('domready时间 :' + (t.domContentLoadedEventEnd - t.navigationStart).toFixed(0))console.log('onload时间 :' + (t.loadEventEnd - t.navigationStart).toFixed(0))if (t = performance.memory) {console.log('js内存使用占比:' + (t.usedJSHeapSize / t.totalJSHeapSize * 100).toFixed(2) + '%')}})}
47、禁止某些键盘事件
document.addEventListener('keydown', function(event) {return !(112 == event.keyCode || //禁止F1123 == event.keyCode || //禁止F12event.ctrlKey && 82 == event.keyCode || //禁止ctrl+Revent.ctrlKey && 18 == event.keyCode || //禁止ctrl+Nevent.shiftKey && 121 == event.keyCode || //禁止shift+F10event.altKey && 115 == event.keyCode || //禁止alt+F4"A" == event.srcElement.tagName && event.shiftKey //禁止shift+点击a标签) || (event.returnValue = false)});
48、禁止右键、选择、复制
['contextmenu', 'selectstart', 'copy'].forEach(function(ev) {document.addEventListener(ev, function(event) {return event.returnValue = false;})});
49、numAdd - -计算数字相加
function numAdd(num1, num2) {let baseNum, baseNum1, baseNum2;try {baseNum1 = num1.toString().split(".")[1].length;} catch (e) {baseNum1 = 0;}try {baseNum2 = num2.toString().split(".")[1].length;} catch (e) {baseNum2 = 0;}baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));return (num1 * baseNum + num2 * baseNum) / baseNum;};
50、numSub - - 计算数字相减
function numSub(num1, num2) {let baseNum, baseNum1, baseNum2;let precision;// 精度try {baseNum1 = num1.toString().split(".")[1].length;} catch (e) {baseNum1 = 0;}try {baseNum2 = num2.toString().split(".")[1].length;} catch (e) {baseNum2 = 0;}baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2;return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);};
51、numMulti - - 计算数字相乘
function numMulti(num1, num2) {let baseNum = 0;try {baseNum += num1.toString().split(".")[1].length;} catch (e) {}try {baseNum += num2.toString().split(".")[1].length;} catch (e) {}return Number(num1.toString().replace(".", "")) * Number(num2.toString().replace(".", "")) / Math.pow(10, baseNum);};
52、numdiv - - 计算数字相除
function numdiv(num1, num2) {let baseNum1 = 0, baseNum2 = 0;let baseNum3, baseNum4;try {baseNum1 = num1.toString().split(".")[1].length;} catch (e) {baseNum1 = 0;}try {baseNum2 = num2.toString().split(".")[1].length;} catch (e) {baseNum2 = 0;}with (Math) {baseNum3 = Number(num1.toString().replace(".", ""));baseNum4 = Number(num2.toString().replace(".", ""));return (baseNum3 / baseNum4) * pow(10, baseNum2 - baseNum1);}}; ——————————————————————————————————————————————————————————————————————————————
一、类型判断函数
1.1 基础类型判断
javascript
// 判断是否为undefined const isUndefined = val => typeof val === 'undefined'; // 判断是否为null const isNull = val => val === null; // 判断是否为数字(包括数值字符串) const isNumeric = val => !isNaN(parseFloat(val)) && isFinite(val); // 判断是否为纯数字(严格) const isNumber = val => typeof val === 'number' && !isNaN(val); // 判断是否为字符串 const isString = val => typeof val === 'string'; // 判断是否为布尔值 const isBoolean = val => typeof val === 'boolean'; // 判断是否为Symbol const isSymbol = val => typeof val === 'symbol'; // 判断是否为BigInt const isBigInt = val => typeof val === 'bigint'; // 判断是否为函数 const isFunction = val => typeof val === 'function'; // 判断是否为对象(包括数组、日期等) const isObject = val => val !== null && typeof val === 'object'; // 判断是否为纯对象(plain object) const isPlainObject = val => Object.prototype.toString.call(val) === '[object Object]'; // 判断是否为数组 const isArray = Array.isArray || (val => Object.prototype.toString.call(val) === '[object Array]'); // 判断是否为日期对象 const isDate = val => val instanceof Date; // 判断是否为正则表达式 const isRegExp = val => val instanceof RegExp; // 判断是否为Promise对象 const isPromise = val => val && typeof val.then === 'function' && typeof val.catch === 'function'; // 判断是否为Map const isMap = val => val instanceof Map; // 判断是否为Set const isSet = val => val instanceof Set; // 判断是否为FormData const isFormData = val => val instanceof FormData; // 判断是否为File const isFile = val => val instanceof File;
1.2 复合类型判断
javascript
// 判断是否为空值(undefined、null、空字符串、空数组、空对象)
const isEmpty = val => {
if (val == null) return true;
if (typeof val === 'string' || Array.isArray(val)) return val.length === 0;
if (typeof val === 'object') {
if (val instanceof Map || val instanceof Set) return val.size === 0;
return Object.keys(val).length === 0;
}
return false;
};
// 判断是否为类数组对象
const isArrayLike = val => {
if (val == null || typeof val === 'function') return false;
return typeof val.length === 'number' && val.length >= 0;
};
// 判断是否为DOM元素
const isElement = val => val instanceof Element;
// 判断是否为NodeList
const isNodeList = val => val instanceof NodeList;
// 判断是否为HTMLCollection
const isHTMLCollection = val => val instanceof HTMLCollection;
// 类型获取
const getType = val =>
Object.prototype.toString.call(val).slice(8, -1).toLowerCase();
二、数学运算函数
2.1 基本数学运算
javascript
// 生成指定范围随机整数
const randomInt = (min, max) =>
Math.floor(Math.random() * (max - min + 1)) + min;
// 生成指定范围随机浮点数
const randomFloat = (min, max) =>
Math.random() * (max - min) + min;
// 限制数字在指定范围内
const clamp = (num, min, max) =>
Math.min(Math.max(num, min), max);
// 将数字映射到另一个范围
const mapRange = (num, inMin, inMax, outMin, outMax) =>
((num - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
// 线性插值
const lerp = (start, end, amt) =>
(1 - amt) * start + amt * end;
// 计算两点间距离
const distance = (x1, y1, x2, y2) =>
Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
// 计算阶乘
const factorial = n => {
if (n < 0) return NaN;
if (n === 0 || n === 1) return 1;
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
};
// 数字千分位格式化
const formatNumber = (num, decimals = 0) => {
if (!isNumeric(num)) return '0';
const number = parseFloat(num);
const parts = number.toFixed(decimals).split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
};
// 生成UUID
const generateUUID = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
// 生成短ID
const generateShortId = (length = 8) => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
};
2.2 金融计算
javascript
// 精确加法(解决浮点数精度问题)
const preciseAdd = (...args) => {
const m = Math.pow(10, Math.max(...args.map(num => {
const str = num.toString();
return str.includes('.') ? str.split('.')[1].length : 0;
})));
return args.reduce((sum, num) => sum + Math.round(num * m), 0) / m;
};
// 精确乘法
const preciseMultiply = (...args) => {
const m = args.reduce((product, num) => {
const str = num.toString();
const decimalPlaces = str.includes('.') ? str.split('.')[1].length : 0;
return product + decimalPlaces;
}, 0);
const multiplier = Math.pow(10, m);
return args.reduce((product, num) =>
product * (Math.round(num * multiplier) / multiplier), 1);
};
// 计算百分比
const calculatePercentage = (value, total, decimals = 2) => {
if (total === 0) return 0;
return Number(((value / total) * 100).toFixed(decimals));
};
// 格式化货币
const formatCurrency = (amount, currency = 'CNY', locale = 'zh-CN') => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: currency
}).format(amount);
};
三、字符串操作函数
3.1 字符串处理
javascript
// 去除字符串两端空格
const trim = str => str.trim();
// 去除字符串所有空格
const removeAllSpaces = str => str.replace(/\s+/g, '');
// 首字母大写
const capitalize = str =>
str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
// 每个单词首字母大写
const capitalizeWords = str =>
str.replace(/\b\w/g, char => char.toUpperCase());
// 转换为驼峰命名
const toCamelCase = str =>
str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
// 转换为帕斯卡命名
const toPascalCase = str => {
const camel = toCamelCase(str);
return camel.charAt(0).toUpperCase() + camel.slice(1);
};
// 转换为烤肉串命名(kebab-case)
const toKebabCase = str =>
str && str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.toLowerCase())
.join('-');
// 转换为蛇形命名(snake_case)
const toSnakeCase = str =>
str && str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.toLowerCase())
.join('_');
// 截断字符串并添加省略号
const truncate = (str, length, end = '...') =>
str.length > length ? str.substring(0, length - end.length) + end : str;
// 反转字符串
const reverseString = str => str.split('').reverse().join('');
// 判断是否为回文字符串
const isPalindrome = str => {
const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return cleaned === cleaned.split('').reverse().join('');
};
// 统计字符出现次数
const charCount = (str, char) =>
str.split('').filter(c => c === char).length;
// 生成指定长度随机字符串
const randomString = (length = 8) => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
return Array.from({ length }, () =>
chars.charAt(Math.floor(Math.random() * chars.length))).join('');
};
3.2 字符串验证
javascript
// 验证邮箱格式
const isValidEmail = email =>
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
// 验证手机号格式(中国)
const isValidPhoneCN = phone =>
/^1[3-9]\d{9}$/.test(phone);
// 验证身份证号格式(中国)
const isValidIdCardCN = id => {
const reg = /^\d{17}[\dXx]$/;
if (!reg.test(id)) return false;
// 校验码验证
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
const codes = '10X98765432';
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += parseInt(id.charAt(i)) * weights[i];
}
const code = codes.charAt(sum % 11);
return code === id.charAt(17).toUpperCase();
};
// 验证URL格式
const isValidURL = url => {
try {
new URL(url);
return true;
} catch {
return false;
}
};
// 验证强密码(至少8位,包含大小写字母和数字)
const isStrongPassword = password =>
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,}$/.test(password);
// 验证IPv4地址
const isValidIPv4 = ip =>
/^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/.test(ip);
// 验证是否为中文
const isChinese = str =>
/^[\u4e00-\u9fa5]+$/.test(str);
// 验证是否为数字字符串
const isNumericString = str =>
/^\d+$/.test(str);
四、数组操作函数
4.1 数组创建和转换
javascript
// 创建指定范围的数字数组
const range = (start, end, step = 1) => {
const result = [];
if (step > 0) {
for (let i = start; i <= end; i += step) result.push(i);
} else {
for (let i = start; i >= end; i += step) result.push(i);
}
return result;
};
// 创建指定长度的填充数组
const fillArray = (length, value) =>
Array.from({ length }, () => value);
// 创建指定长度的递增数组
const sequence = (length, start = 0, step = 1) =>
Array.from({ length }, (_, i) => start + i * step);
// 将类数组转换为数组
const toArray = arrayLike =>
Array.from ? Array.from(arrayLike) : Array.prototype.slice.call(arrayLike);
// 数组扁平化(单层)
const flatten = arr =>
arr.reduce((acc, val) => acc.concat(val), []);
// 数组深度扁平化
const flattenDeep = arr =>
arr.reduce((acc, val) =>
acc.concat(Array.isArray(val) ? flattenDeep(val) : val), []);
// 数组去重
const unique = arr =>
Array.from(new Set(arr));
// 根据条件去重
const uniqueBy = (arr, key) => {
const seen = new Set();
return arr.filter(item => {
const val = typeof key === 'function' ? key(item) : item[key];
if (seen.has(val)) return false;
seen.add(val);
return true;
});
};
// 数组分块
const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size));
4.2 数组查找和操作
javascript
// 查找数组中的最大值
const max = arr => Math.max(...arr);
// 查找数组中的最小值
const min = arr => Math.min(...arr);
// 查找数组中的最大值索引
const maxIndex = arr =>
arr.reduce((maxIdx, val, idx, array) =>
val > array[maxIdx] ? idx : maxIdx, 0);
// 查找数组中的最小值索引
const minIndex = arr =>
arr.reduce((minIdx, val, idx, array) =>
val < array[minIdx] ? idx : minIdx, 0);
// 数组求和
const sum = arr => arr.reduce((acc, val) => acc + val, 0);
// 数组平均值
const average = arr => arr.reduce((acc, val) => acc + val, 0) / arr.length;
// 数组分组
const groupBy = (arr, key) => {
return arr.reduce((acc, obj) => {
const keyValue = typeof key === 'function' ? key(obj) : obj[key];
if (!acc[keyValue]) acc[keyValue] = [];
acc[keyValue].push(obj);
return acc;
}, {});
};
// 数组排序(稳定排序)
const stableSort = (arr, compare) => {
return arr
.map((item, index) => ({ item, index }))
.sort((a, b) => compare(a.item, b.item) || a.index - b.index)
.map(({ item }) => item);
};
// 数组交集
const intersection = (arr1, arr2) =>
arr1.filter(item => arr2.includes(item));
// 数组并集
const union = (arr1, arr2) =>
Array.from(new Set([...arr1, ...arr2]));
// 数组差集
const difference = (arr1, arr2) =>
arr1.filter(item => !arr2.includes(item));
// 数组对称差集
const symmetricDifference = (arr1, arr2) =>
arr1.filter(item => !arr2.includes(item))
.concat(arr2.filter(item => !arr1.includes(item)));
// 随机打乱数组(Fisher-Yates算法)
const shuffle = arr => {
const result = [...arr];
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return result;
};
// 随机获取数组元素
const sample = arr =>
arr[Math.floor(Math.random() * arr.length)];
// 获取数组随机多个元素
const sampleSize = (arr, size = 1) => {
const shuffled = shuffle(arr);
return shuffled.slice(0, Math.min(size, shuffled.length));
};
4.3 数组高级操作
javascript
// 数组笛卡尔积
const cartesianProduct = (...arrays) =>
arrays.reduce((acc, curr) =>
acc.flatMap(x => curr.map(y => [...x, y])), [[]]);
// 数组排列组合
const permutations = arr => {
if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr;
return arr.reduce((acc, item, i) =>
acc.concat(permutations([...arr.slice(0, i), ...arr.slice(i + 1)])
.map(val => [item, ...val])), []);
};
// 数组滑动窗口
const slidingWindow = (arr, size) => {
if (size > arr.length) return [];
const result = [];
for (let i = 0; i <= arr.length - size; i++) {
result.push(arr.slice(i, i + size));
}
return result;
};
// 数组压缩(将多个数组按位置合并)
const zip = (...arrays) => {
const maxLength = Math.max(...arrays.map(arr => arr.length));
return Array.from({ length: maxLength }, (_, i) =>
arrays.map(arr => arr[i]));
};
// 数组解压缩
const unzip = arrays =>
arrays[0].map((_, i) => arrays.map(arr => arr[i]));
五、对象操作函数
5.1 对象创建和转换
javascript
// 深度克隆对象
const deepClone = obj => {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj.getTime());
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Map) return new Map(Array.from(obj.entries()));
if (obj instanceof Set) return new Set(Array.from(obj.values()));
const clone = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
};
// 对象合并(深度合并)
const deepMerge = (target, source) => {
const result = { ...target };
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (source[key] && typeof source[key] === 'object' &&
!Array.isArray(source[key]) &&
!(source[key] instanceof Date) &&
!(source[key] instanceof RegExp) &&
target[key] && typeof target[key] === 'object') {
result[key] = deepMerge(target[key], source[key]);
} else {
result[key] = source[key];
}
}
}
return result;
};
// 对象扁平化
const flattenObject = (obj, prefix = '') => {
return Object.keys(obj).reduce((acc, key) => {
const pre = prefix.length ? `${prefix}.` : '';
if (typeof obj[key] === 'object' && obj[key] !== null &&
!Array.isArray(obj[key]) && !(obj[key] instanceof Date)) {
Object.assign(acc, flattenObject(obj[key], pre + key));
} else {
acc[pre + key] = obj[key];
}
return acc;
}, {});
};
// 对象反扁平化
const unflattenObject = obj => {
return Object.keys(obj).reduce((acc, key) => {
const keys = key.split('.');
let current = acc;
for (let i = 0; i < keys.length - 1; i++) {
if (!current[keys[i]] || typeof current[keys[i]] !== 'object') {
current[keys[i]] = {};
}
current = current[keys[i]];
}
current[keys[keys.length - 1]] = obj[key];
return acc;
}, {});
};
5.2 对象查询和操作
javascript
// 安全获取嵌套对象属性
const get = (obj, path, defaultValue = undefined) => {
const travel = regexp =>
String.prototype.split
.call(path, regexp)
.filter(Boolean)
.reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
return result === undefined || result === obj ? defaultValue : result;
};
// 设置嵌套对象属性
const set = (obj, path, value) => {
if (Object(obj) !== obj) return obj;
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || [];
path.slice(0, -1).reduce((a, c, i) =>
Object(a[c]) === a[c] ? a[c] : a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {}, obj)[path[path.length - 1]] = value;
return obj;
};
// 检查对象是否包含路径
const has = (obj, path) => {
if (Object(obj) !== obj) return false;
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || [];
for (let i = 0; i < path.length; i++) {
if (!obj.hasOwnProperty(path[i])) return false;
obj = obj[path[i]];
}
return true;
};
// 对象过滤(根据条件)
const filterObject = (obj, predicate) => {
return Object.keys(obj)
.filter(key => predicate(obj[key], key))
.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
};
// 对象映射
const mapObject = (obj, fn) => {
return Object.keys(obj).reduce((acc, key) => {
acc[key] = fn(obj[key], key);
return acc;
}, {});
};
// 对象键值对反转
const invertObject = obj => {
return Object.keys(obj).reduce((acc, key) => {
acc[obj[key]] = key;
return acc;
}, {});
};
// 对象浅比较
const shallowEqual = (obj1, obj2) => {
if (obj1 === obj2) return true;
if (typeof obj1 !== 'object' || obj1 === null ||
typeof obj2 !== 'object' || obj2 === null) {
return false;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (const key of keys1) {
if (obj1[key] !== obj2[key] || !keys2.includes(key)) {
return false;
}
}
return true;
};
// 对象深度比较
const deepEqual = (obj1, obj2) => {
if (obj1 === obj2) return true;
if (obj1 == null || obj2 == null ||
typeof obj1 !== 'object' || typeof obj2 !== 'object') {
return obj1 === obj2;
}
if (obj1.constructor !== obj2.constructor) return false;
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (const key of keys1) {
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
};
// 对象转换为查询字符串
const objectToQueryString = obj => {
return Object.keys(obj)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
.join('&');
};
// 查询字符串转换为对象
const queryStringToObject = queryString => {
return queryString.split('&').reduce((acc, pair) => {
const [key, value] = pair.split('=');
if (key) {
acc[decodeURIComponent(key)] = decodeURIComponent(value || '');
}
return acc;
}, {});
};
六、函数操作函数
6.1 函数包装和修饰
javascript
// 防抖函数
const debounce = (func, wait, immediate = false) => {
let timeout;
return function executedFunction(...args) {
const context = this;
const later = () => {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// 节流函数
const throttle = (func, limit) => {
let inThrottle;
return function(...args) {
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
};
// 函数柯里化
const curry = (func, arity = func.length) => {
return function curried(...args) {
if (args.length >= arity) return func.apply(this, args);
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
};
};
// 函数组合
const compose = (...funcs) =>
funcs.reduce((f, g) => (...args) => f(g(...args)));
// 管道函数(从左到右执行)
const pipe = (...funcs) =>
funcs.reduce((f, g) => (...args) => g(f(...args)));
// 函数记忆化
const memoize = func => {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = func.apply(this, args);
cache.set(key, result);
return result;
};
};
// 函数只执行一次
const once = func => {
let called = false;
let result;
return function(...args) {
if (!called) {
called = true;
result = func.apply(this, args);
}
return result;
};
};
// 延迟执行函数
const delay = (func, wait, ...args) =>
setTimeout(() => func.apply(null, args), wait);
// 函数重试机制
const retry = async (func, retries = 3, delay = 1000) => {
for (let i = 0; i < retries; i++) {
try {
return await func();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};
// 创建安全函数(捕获异常)
const safe = func => {
return function(...args) {
try {
return func.apply(this, args);
} catch (error) {
console.error('Function execution failed:', error);
return null;
}
};
};
6.2 函数高级操作
javascript
// 部分应用函数
const partial = (func, ...partialArgs) => {
return function(...remainingArgs) {
return func.apply(this, [...partialArgs, ...remainingArgs]);
};
};
// 绑定函数上下文
const bind = (func, context, ...args) =>
func.bind(context, ...args);
// 函数时间测量
const time = (func, label = 'Function') => {
return function(...args) {
console.time(label);
const result = func.apply(this, args);
console.timeEnd(label);
return result;
};
};
// 异步函数超时控制
const withTimeout = (asyncFunc, timeout, errorMessage = 'Timeout') => {
return function(...args) {
return Promise.race([
asyncFunc.apply(this, args),
new Promise((_, reject) =>
setTimeout(() => reject(new Error(errorMessage)), timeout)
)
]);
};
};
// 批量执行异步函数
const parallel = async (funcs, concurrency = 5) => {
const results = [];
const executing = new Set();
for (let i = 0; i < funcs.length; i++) {
const func = funcs[i];
const promise = func().then(result => {
results[i] = result;
executing.delete(promise);
});
executing.add(promise);
if (executing.size >= concurrency) {
await Promise.race(executing);
}
}
await Promise.all(executing);
return results;
};
// 顺序执行异步函数
const series = async funcs => {
const results = [];
for (const func of funcs) {
results.push(await func());
}
return results;
};
七、日期时间函数
7.1 日期创建和格式化
javascript
// 获取当前时间戳(秒)
const timestamp = () => Math.floor(Date.now() / 1000);
// 格式化日期
const formatDate = (date = new Date(), format = 'YYYY-MM-DD') => {
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
const hours = String(d.getHours()).padStart(2, '0');
const minutes = String(d.getMinutes()).padStart(2, '0');
const seconds = String(d.getSeconds()).padStart(2, '0');
return format
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds);
};
// 解析日期字符串
const parseDate = str => {
const date = new Date(str);
return isNaN(date.getTime()) ? null : date;
};
// 获取相对时间(如"2小时前")
const relativeTime = (date, lang = 'zh-CN') => {
const now = new Date();
const d = new Date(date);
const diff = now - d;
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const months = Math.floor(days / 30);
const years = Math.floor(months / 12);
const messages = {
'zh-CN': {
now: '刚刚',
seconds: '秒前',
minutes: '分钟前',
hours: '小时前',
days: '天前',
months: '个月前',
years: '年前'
},
'en-US': {
now: 'just now',
seconds: 'seconds ago',
minutes: 'minutes ago',
hours: 'hours ago',
days: 'days ago',
months: 'months ago',
years: 'years ago'
}
};
const msg = messages[lang] || messages['zh-CN'];
if (seconds < 10) return msg.now;
if (seconds < 60) return `${seconds}${msg.seconds}`;
if (minutes < 60) return `${minutes}${msg.minutes}`;
if (hours < 24) return `${hours}${msg.hours}`;
if (days < 30) return `${days}${msg.days}`;
if (months < 12) return `${months}${msg.months}`;
return `${years}${msg.years}`;
};
// 获取日期范围
const getDateRange = (start, end) => {
const dates = [];
const current = new Date(start);
const last = new Date(end);
while (current <= last) {
dates.push(new Date(current));
current.setDate(current.getDate() + 1);
}
return dates;
};
// 计算两个日期的差值
const dateDiff = (date1, date2, unit = 'days') => {
const d1 = new Date(date1);
const d2 = new Date(date2);
const diff = Math.abs(d2 - d1);
switch (unit) {
case 'milliseconds': return diff;
case 'seconds': return Math.floor(diff / 1000);
case 'minutes': return Math.floor(diff / (1000 * 60));
case 'hours': return Math.floor(diff / (1000 * 60 * 60));
case 'days': return Math.floor(diff / (1000 * 60 * 60 * 24));
case 'weeks': return Math.floor(diff / (1000 * 60 * 60 * 24 * 7));
default: return Math.floor(diff / (1000 * 60 * 60 * 24));
}
};
7.2 日期操作
javascript
// 添加时间
const addTime = (date, amount, unit = 'days') => {
const d = new Date(date);
switch (unit) {
case 'milliseconds': d.setMilliseconds(d.getMilliseconds() + amount); break;
case 'seconds': d.setSeconds(d.getSeconds() + amount); break;
case 'minutes': d.setMinutes(d.getMinutes() + amount); break;
case 'hours': d.setHours(d.getHours() + amount); break;
case 'days': d.setDate(d.getDate() + amount); break;
case 'months': d.setMonth(d.getMonth() + amount); break;
case 'years': d.setFullYear(d.getFullYear() + amount); break;
}
return d;
};
// 获取月份的第一天
const startOfMonth = date => {
const d = new Date(date);
d.setDate(1);
d.setHours(0, 0, 0, 0);
return d;
};
// 获取月份的最后一天
const endOfMonth = date => {
const d = new Date(date);
d.setMonth(d.getMonth() + 1);
d.setDate(0);
d.setHours(23, 59, 59, 999);
return d;
};
// 获取周的第一天(周一)
const startOfWeek = (date, startDay = 1) => {
const d = new Date(date);
const day = d.getDay();
const diff = (day < startDay ? 7 : 0) + day - startDay;
d.setDate(d.getDate() - diff);
d.setHours(0, 0, 0, 0);
return d;
};
// 获取周的最后一天(周日)
const endOfWeek = (date, startDay = 1) => {
const d = startOfWeek(date, startDay);
d.setDate(d.getDate() + 6);
d.setHours(23, 59, 59, 999);
return d;
};
// 判断是否为闰年
const isLeapYear = year =>
(year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
// 获取月份的天数
const getDaysInMonth = (year, month) =>
new Date(year, month + 1, 0).getDate();
// 判断两个日期是否在同一天
const isSameDay = (date1, date2) => {
const d1 = new Date(date1);
const d2 = new Date(date2);
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();
};
// 获取年龄
const getAge = birthDate => {
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
};
八、浏览器和DOM操作函数
8.1 DOM操作
javascript
// 创建元素
const createElement = (tag, attributes = {}, children = []) => {
const element = document.createElement(tag);
// 设置属性
for (const [key, value] of Object.entries(attributes)) {
if (key === 'className') {
element.className = value;
} else if (key === 'style' && typeof value === 'object') {
Object.assign(element.style, value);
} else if (key.startsWith('on') && typeof value === 'function') {
element.addEventListener(key.substring(2).toLowerCase(), value);
} else {
element.setAttribute(key, value);
}
}
// 添加子元素
children.forEach(child => {
if (typeof child === 'string') {
element.appendChild(document.createTextNode(child));
} else if (child instanceof Node) {
element.appendChild(child);
}
});
return element;
};
// 查询元素
const $ = selector => document.querySelector(selector);
const $$ = selector => Array.from(document.querySelectorAll(selector));
// 获取元素样式
const getStyle = (element, property) =>
window.getComputedStyle(element).getPropertyValue(property);
// 设置元素样式
const setStyle = (element, styles) => {
Object.assign(element.style, styles);
};
// 添加类名
const addClass = (element, className) => {
if (typeof className === 'string') {
element.classList.add(...className.split(' '));
}
};
// 移除类名
const removeClass = (element, className) => {
if (typeof className === 'string') {
element.classList.remove(...className.split(' '));
}
};
// 切换类名
const toggleClass = (element, className, force) => {
if (typeof className === 'string') {
className.split(' ').forEach(name => {
element.classList.toggle(name, force);
});
}
};
// 检查是否包含类名
const hasClass = (element, className) =>
element.classList.contains(className);
// 获取元素位置和尺寸
const getRect = element => {
const rect = element.getBoundingClientRect();
return {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left,
width: rect.width,
height: rect.height,
x: rect.x,
y: rect.y
};
};
// 元素是否在视口中
const isInViewport = element => {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
// 监听元素进入视口
const observeIntersection = (element, callback, options = {}) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
callback(entry);
}
});
}, options);
observer.observe(element);
return observer;
};
8.2 事件处理
javascript
// 事件委托
const delegate = (selector, event, handler) => {
return function(event) {
const target = event.target;
const closest = target.closest(selector);
if (closest && this.contains(closest)) {
handler.call(closest, event);
}
};
};
// 一次性事件监听
const onceEvent = (element, event, handler) => {
const onceHandler = e => {
handler(e);
element.removeEventListener(event, onceHandler);
};
element.addEventListener(event, onceHandler);
};
// 防抖事件监听
const debounceEvent = (element, event, handler, wait) => {
const debounced = debounce(handler, wait);
element.addEventListener(event, debounced);
return () => element.removeEventListener(event, debounced);
};
// 节流事件监听
const throttleEvent = (element, event, handler, limit) => {
const throttled = throttle(handler, limit);
element.addEventListener(event, throttled);
return () => element.removeEventListener(event, throttled);
};
// 获取鼠标位置
const getMousePosition = event => ({
x: event.clientX,
y: event.clientY,
pageX: event.pageX,
pageY: event.pageY
});
// 获取触摸位置
const getTouchPosition = event => {
if (event.touches && event.touches.length > 0) {
return {
x: event.touches[0].clientX,
y: event.touches[0].clientY,
pageX: event.touches[0].pageX,
pageY: event.touches[0].pageY
};
}
return { x: 0, y: 0, pageX: 0, pageY: 0 };
};
// 阻止事件冒泡
const stopPropagation = event => event.stopPropagation();
// 阻止默认行为
const preventDefault = event => event.preventDefault();
// 触发自定义事件
const triggerEvent = (element, eventName, detail = {}) => {
const event = new CustomEvent(eventName, { detail, bubbles: true });
element.dispatchEvent(event);
};
8.3 浏览器存储
javascript
// 本地存储封装
const storage = {
// 设置值
set(key, value, expires = null) {
const item = {
value,
expires: expires ? Date.now() + expires * 1000 : null
};
localStorage.setItem(key, JSON.stringify(item));
},
// 获取值
get(key) {
const itemStr = localStorage.getItem(key);
if (!itemStr) return null;
try {
const item = JSON.parse(itemStr);
if (item.expires && Date.now() > item.expires) {
localStorage.removeItem(key);
return null;
}
return item.value;
} catch {
return null;
}
},
// 删除值
remove(key) {
localStorage.removeItem(key);
},
// 清空
clear() {
localStorage.clear();
},
// 获取所有键
keys() {
return Object.keys(localStorage);
}
};
// Cookie操作
const cookie = {
// 设置Cookie
set(name, value, days = 7, path = '/') {
const expires = new Date(Date.now() + days * 864e5).toUTCString();
document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=${path}`;
},
// 获取Cookie
get(name) {
return document.cookie.split('; ').reduce((acc, cookie) => {
const [key, val] = cookie.split('=');
if (key === name) acc = decodeURIComponent(val);
return acc;
}, '');
},
// 删除Cookie
remove(name, path = '/') {
this.set(name, '', -1, path);
},
// 获取所有Cookie
getAll() {
return document.cookie.split('; ').reduce((acc, cookie) => {
const [key, val] = cookie.split('=');
acc[key] = decodeURIComponent(val);
return acc;
}, {});
}
};
九、网络请求函数
9.1 HTTP请求
javascript
// 通用请求函数
const request = async (url, options = {}) => {
const {
method = 'GET',
headers = {},
body = null,
timeout = 10000,
...restOptions
} = options;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
...headers
},
body: body ? JSON.stringify(body) : null,
signal: controller.signal,
...restOptions
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
return await response.text();
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('请求超时');
}
throw error;
}
};
// GET请求
const get = (url, options = {}) =>
request(url, { ...options, method: 'GET' });
// POST请求
const post = (url, data = {}, options = {}) =>
request(url, { ...options, method: 'POST', body: data });
// PUT请求
const put = (url, data = {}, options = {}) =>
request(url, { ...options, method: 'PUT', body: data });
// DELETE请求
const del = (url, options = {}) =>
request(url, { ...options, method: 'DELETE' });
// PATCH请求
const patch = (url, data = {}, options = {}) =>
request(url, { ...options, method: 'PATCH', body: data });
// 并发请求
const concurrentRequests = async (requests, maxConcurrent = 5) => {
const results = [];
const executing = new Set();
for (let i = 0; i < requests.length; i++) {
const request = requests[i];
const promise = request().then(result => {
results[i] = { success: true, data: result };
executing.delete(promise);
}).catch(error => {
results[i] = { success: false, error };
executing.delete(promise);
});
executing.add(promise);
if (executing.size >= maxConcurrent) {
await Promise.race(executing);
}
}
await Promise.all(executing);
return results;
};
// 轮询请求
const poll = async (url, options = {}, interval = 5000, timeout = 60000) => {
const startTime = Date.now();
return new Promise((resolve, reject) => {
const pollInterval = setInterval(async () => {
if (Date.now() - startTime > timeout) {
clearInterval(pollInterval);
reject(new Error('轮询超时'));
return;
}
try {
const result = await request(url, options);
resolve(result);
clearInterval(pollInterval);
} catch (error) {
// 继续轮询
}
}, interval);
});
};
9.2 文件操作
javascript
// 文件转Base64
const fileToBase64 = file => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
};
// Base64转文件
const base64ToFile = (base64, filename, mimeType) => {
const arr = base64.split(',');
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mimeType });
};
// 下载文件
const downloadFile = (content, filename, type = 'text/plain') => {
const blob = new Blob([content], { type });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
// 图片压缩
const compressImage = (file, maxWidth = 800, quality = 0.8) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = e => {
const img = new Image();
img.src = e.target.result;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let width = img.width;
let height = img.height;
if (width > maxWidth) {
height = Math.round((height * maxWidth) / width);
width = maxWidth;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(
blob => resolve(blob),
file.type,
quality
);
};
img.onerror = reject;
};
reader.onerror = reject;
});
};
// 文件大小格式化
const formatFileSize = bytes => {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
十、其他实用函数
10.1 性能优化
javascript
// 空闲时间执行任务
const idleTask = (task, timeout = 1000) => {
if ('requestIdleCallback' in window) {
return new Promise(resolve => {
requestIdleCallback(() => {
task();
resolve();
}, { timeout });
});
}
return new Promise(resolve => {
setTimeout(() => {
task();
resolve();
}, 0);
});
};
// 批量更新
const batchUpdate = (callback, timeout = 0) => {
return setTimeout(callback, timeout);
};
// 图片懒加载
const lazyLoadImages = (selector = 'img[data-src]') => {
const images = document.querySelectorAll(selector);
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
};
// 虚拟列表渲染
const virtualList = (container, items, itemHeight, renderItem) => {
let visibleItems = [];
let startIndex = 0;
const updateVisibleItems = () => {
const scrollTop = container.scrollTop;
const containerHeight = container.clientHeight;
const visibleCount = Math.ceil(containerHeight / itemHeight);
startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(startIndex + visibleCount + 2, items.length);
const newVisibleItems = items.slice(startIndex, endIndex);
if (JSON.stringify(newVisibleItems) !== JSON.stringify(visibleItems)) {
visibleItems = newVisibleItems;
container.innerHTML = '';
visibleItems.forEach((item, index) => {
const element = renderItem(item, startIndex + index);
element.style.position = 'absolute';
element.style.top = `${(startIndex + index) * itemHeight}px`;
container.appendChild(element);
});
container.style.height = `${items.length * itemHeight}px`;
}
};
container.addEventListener('scroll', updateVisibleItems);
updateVisibleItems();
};
10.2 安全函数
javascript
// XSS过滤
const xssFilter = str => {
if (typeof str !== 'string') return str;
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/');
};
// HTML实体编码
const encodeHTML = str => {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
};
// HTML实体解码
const decodeHTML = str => {
const div = document.createElement('div');
div.innerHTML = str;
return div.textContent;
};
// 密码强度检测
const passwordStrength = password => {
let score = 0;
if (password.length < 6) return 0;
if (password.length >= 8) score += 1;
if (password.length >= 12) score += 1;
if (/[a-z]/.test(password)) score += 1;
if (/[A-Z]/.test(password)) score += 1;
if (/[0-9]/.test(password)) score += 1;
if (/[^a-zA-Z0-9]/.test(password)) score += 1;
const levels = ['非常弱', '弱', '一般', '强', '非常强'];
return levels[Math.min(score, levels.length - 1)];
};
10.3 调试函数
javascript
// 性能计时
const perfTimer = label => {
console.time(label);
return () => console.timeEnd(label);
};
// 条件日志
const conditionalLog = (condition, ...args) => {
if (condition) {
console.log(...args);
}
};
// 深度日志(避免循环引用)
const deepLog = obj => {
console.log(JSON.stringify(obj, null, 2));
};
// 函数调用追踪
const trace = label => {
return function(...args) {
console.log(`[${label}] 调用参数:`, args);
const result = this.apply(this, args);
console.log(`[${label}] 返回结果:`, result);
return result;
};
};
使用示例
javascript
// 示例1:使用防抖函数
const searchInput = document.getElementById('search');
const searchHandler = debounce(async (event) => {
const results = await searchAPI(event.target.value);
displayResults(results);
}, 300);
searchInput.addEventListener('input', searchHandler);
// 示例2:使用对象深拷贝
const original = { a: 1, b: { c: 2, d: [3, 4] } };
const cloned = deepClone(original);
// 示例3:使用日期格式化
const today = new Date();
console.log(formatDate(today, 'YYYY年MM月DD日 HH:mm:ss'));
// 示例4:使用网络请求
async function fetchData() {
try {
const data = await get('/api/users');
const user = await get(`/api/users/${data[0].id}`);
console.log(user);
} catch (error) {
console.error('请求失败:', error);
}
}
// 示例5:使用数组操作
const numbers = [1, 2, 3, 4, 5, 2, 3, 6];
const uniqueNumbers = unique(numbers); // [1, 2, 3, 4, 5, 6]
const chunked = chunk(numbers, 3); // [[1,2,3], [4,5,2], [3,6]]
// 示例6:使用函数组合
const add = (x, y) => x + y;
const multiply = (x, y) => x * y;
const add5 = curry(add)(5);
const multiplyBy3 = curry(multiply)(3);
const composed = compose(add5, multiplyBy3);
console.log(composed(10)); // 35
// 示例7:使用存储封装
storage.set('user', { name: '张三', age: 25 }, 3600); // 1小时后过期
const user = storage.get('user');
总结
本文整理了JavaScript中常用的工具函数,涵盖了类型判断、数学运算、字符串处理、数组操作、对象处理、函数操作、日期时间处理、浏览器DOM操作、网络请求等多个方面。这些函数可以直接复制使用,也可以根据实际需求进行修改和扩展。
更多推荐
所有评论(0)