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 < 11        type: "IE",        version: Number(t.match(/msie ([\d]+)/)[1])    } : !!t.match(/trident\/.+?rv:(([\d.]+))/) ? { // ie 11        type: "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] = true                result.push(item)            }        }else{//引用类型及symbol            if(!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]转化为.0      path = 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 || 0    upper = +upper || 0    return 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 = this    let 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 || this        let 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 ||        //禁止F1        123 == event.keyCode ||        //禁止F12        event.ctrlKey && 82 == event.keyCode ||        //禁止ctrl+R        event.ctrlKey && 18 == event.keyCode ||        //禁止ctrl+N        event.shiftKey && 121 == event.keyCode ||          //禁止shift+F10        event.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, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#x27;')
    .replace(/\//g, '&#x2F;');
};

// 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操作、网络请求等多个方面。这些函数可以直接复制使用,也可以根据实际需求进行修改和扩展。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐