阅读 1328

总结和整理的常用方法

缘起

本篇文章主要总结了自己常用的和整理收集的,在项目中可能常用到的方法,如果觉得有用的话,点个赞鼓励下,谢谢!

本篇文章配有案列对应的测试用例

Url 类

url 相关方法,url参数序列化/URL参数获取

url参数序列化

 /**
 * URL 参数序列化
 * @param { String } baseURL :url地址
 * @param { Object } params  :参数对象
 * @return 参数序列化后的字符串
 */
 const ParamSerialize = function  (baseURL,params){
    return Object.keys(params).reduce((pre,cur)=> pre += ((pre===baseURL? '?':'&')+`${cur}=${params[cur]}`),baseURL)
}
//测试用例
ParamSerialize('www.baidu.com',{name:'',age:19}) //www.baidu.com?name=&age=19
ParamSerialize('www.baidu.com',{name:'wuming',age:''}) //www.baidu.com?name=wuming&age=
ParamSerialize('www.baidu.com',{name:'wuming',age:19}) //www.baidu.com?name=wuming&age=19
ParamSerialize('www.baidu.com',{})//www.baidu.com
复制代码

URL参数获取

 /**
 * URL 参数获取
 * @param { String } url :url地址  可选,不传则默认值是window.location.href
 * @return object
 */
const getUrlParms = function (url){
    return  (url?url:location.href).includes('?')?(url?url:location.href).split('?')[1].match(/([^&=]*)=([^&]*)/g).reduce((pre,cur)=> {pre[cur.split('=')[0]] = cur.split('=')[1];return pre},{}):{}
}
//测试用例
getUrlParms('www.baidu.com?name=&age=19') //{name: "", age: "19"}
getUrlParms('www.baidu.com?name=wuming&age=') //{name: "wuming", age: ""}
getUrlParms('www.baidu.com?name=wuming&age=19') //{name: "wuming", age: "19"}
getUrlParms('www.baidu.com') //{}
getUrlParms() //当前页面的window.location.href = 'www.baidu.com?name=wuming&age=29',则返回 {name: "wuming", age: "19"}
getUrlParms() //当前页面的window.location.href = 'www.baidu.com',则返回 {}
复制代码

URL模板格式化

/**
 * 请求相关:
 * 
 *  @param {String}  URL: 模板路径,例:'/uap/msg/announcementRecord/{sysId}/{tenantId}/{userId}' 或 '/uap/msg/announcementRecord'
 *  @param {Object}  params: 传入的参数,包含路径参数 或 不包含
 *  @param {Boolean} flag:是否拼接路径和查询参数
 * 
 *  PS:flag为true时,一定是GET请求,GET请求才会拼接参数到URL后面
 */

function getFormatUrl(URL, params, flag=false) {
    let url =/\{(\w+)\}/g.test(URL)?URL.replace(/\{(\w+)\}/g, (a, b) => {let tmp = params[b];delete params[b];return tmp}):URL
    return flag? Object.keys(params).reduce((pre, cur) =>(pre += (pre === url ? '?' : '&') + `${cur}=${params[cur]}`), url): url
}

//测试用例
getFormatUrl('/uap/msg/announcementRecord/{sysId}/{tenantId}/{userId}',{
    sysId:"001",
    tenantId:"002",
    userId:"003",
    username:'wuming',
    age:39,
})
//输出:/uap/msg/announcementRecord/001/002/003
getFormatUrl('/uap/msg/announcementRecord/{sysId}/{tenantId}/{userId}',{
    sysId:"001",
    tenantId:"002",
    userId:"003",
    username:'wuming',
    age:39,
},true)
//输出:/uap/msg/announcementRecord/001/002/003?username=wuming&age=39
getFormatUrl('/uap/msg/announcementRecord',{}) // 输出:/uap/msg/announcementRecord
getUrl('/api/getUerInfo/{userId}/{roleId}',{userId:12,roleId:33})//输出:api/getUerInfo/12/33
getUrl('/api/getUerInfo/{userId}/{roleId}',{userId:12,roleId:33,extraParam:'555'})//输出:api/getUerInfo/12/33
getUrl('/api/getUerInfo/{userId}/{roleId}',{userId:12,roleId:33,extraParam:'555'},true)//输出:/api/getUerInfo/12/33?extraParam=555
复制代码

Generater 类

快速生成类,快速生成 随机字符串/随机数数组

随机字符串

/**
 * 生成随机字符串
 * @param {Number} len 随机字符串的长度 随机不重复字符串长度最大为62
 * @param {Boolean} isRepeat 是否重复 默认true
 * @return 长度为len的随机字符串
 */
const randomStr =  function (count,isRepeat=true){
    var strArr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split(''),res = '';
    var _count = isRepeat===true? count : count > 62? 62 : count;
    while(res.length < _count){
        var random = Math.floor(Math.random()*62)
        if(isRepeat){
            res+=strArr[random]
        }else{
            if(!res.includes(strArr[random])) {
                res+=strArr[random]
            }
        }
    }
    return res
}
//测试用例
randomStr(10)
randomStr(10,false)
randomStr(5)
randomStr(63,false)
randomStr(100)
复制代码

随机数

/**
 * 生成随机数
 * @param {Number | Object} start 范围起始数字
 * @param {Number} end 范围终止数字
 * @param {Number} count 随机数个数
 * @param {Boolean} isRepeat 是否重复
 * @return 随机数数组
 */
const randomNum = function (start,end,count,isRepeat = true){
    var _isRepeat = true;
    if(arguments.length==1 && arguments[0] !==null && typeof arguments[0] === 'object' ){
        var {start,end,count,...reset} = arguments[0]
        _isRepeat = reset.isRepeat=== undefined ?true:reset.isRepeat === false? false : reset.isRepeat ;
    }else{
        _isRepeat = isRepeat
    }
    var _arr= []
    var _max_count =isRepeat? count : end - start + 1
    var _count = count > _max_count? _max_count : count

    while(_arr.length < _count){
        var random = Math.ceil(Math.random()*end)
        var _condition = random>=start && random<=end 
        if(_condition){
            if(_isRepeat){
                _arr.push(random)
            }else{
                !_arr.includes(random) && _arr.push(random)
            }
        }   
    }
    return _arr
}
//测试用例
randomNum(10,20,10)
randomNum(0,9,1)
randomNum(0,9,0)
randomNum(90,100,5,false)
复制代码

Date 类

基于当前 / 指定时间的 过去 n 天时间(包含当天日期)

应用场景:获取过去一周/一月/半年等日期去渲染echarts数据可视化UI

/**
 * 生成 基于当前 / 指定时间的 过去 n 天时间(包含当天日期)
 * @param {Number} days 基于当前 / 指定时间的 过去 n 天时间(包含当天日期)
 * @param {Boolean} s 指定时间
 * @return 日期数组
 */
const passDaysDate = function(days,s)  {
    if(!arguments.length)return [];
    return [...Array(days*1+1).keys()].map(days=>new Date((s?new Date(s):Date.now()) - 86400000 * days).toLocaleDateString()).map(item=>item.split(/\/|-/).map(i=>i.padStart(2,'0')).join('-')).splice(1)
}
//测试用例
passDaysDate()//[]
passDaysDate(3,'2020/3/13')//["2020-03-12", "2020-03-11", "2020-03-10"]
passDaysDate(3)//["2020-03-14", "2020-03-13", "2020-03-12"]
passDaysDate(3,1530975600000) // 13位时间戳日期是:2018/07/07 23:00:00 返回:["2018-07-06", "2018-07-05", "2018-07-04"]
复制代码

生成 范围内所有日期 包含起止日期

/**
 * 生成 范围内所有日期 包含起止日期
 * @param {String | Number} startDate 开始时间
 * @param {String | Number} endDate 结束时间 选填,不填则默认值是当前日期
 * @return 数组
 */
const betweenDate = function(startDate,endDate){
    var arr=[];
    var now=new Date();
    var endDate=endDate?endDate:(now.getFullYear()+'/'+(now.getMonth()+1)+'/'+now.getDate());
    var days=parseInt(Math.abs(new Date(startDate.split(' ')[0]+' 00:00:00') - new Date(endDate.split(' ')[0]+' 00:00:00'))/1000/24/60/60)+1;
    for(let i=0;i<days;i++){
        let stamp=new Date(new Date(startDate).getTime()+i*86400000);
        arr.push(stamp.getFullYear()+'-'+String(stamp.getMonth()+1).padStart(2,0)+'-'+String(stamp.getDate()).padStart(2,0))
    }
    return arr
}
//测试用例
betweenDate('2017-01-01','2017-01-03') //["2017-01-01", "2017-01-02", "2017-01-03"]
betweenDate('2020-03-13') //当前日期:2020/3/15 ,返回 :["2020-03-13", "2020-03-14", "2020-03-15"] 
复制代码

Array 类

快速生成不确定长度值不确定的数组

快速生成不确定数据类型的不确定长度的数组

//方法1
function GenerateArray(len,value){
    return ','.repeat(len-1).split(',').fill(value)
}
//方法2
function GenerateArray(len,value){
    return new Array(len).toString().split(',').fill(value)
}
//方法3
function GenerateArray(len,value){
    return ','.repeat(len-1).split(',').map(i=>value)
}
//方法4
function GenerateArray(len,value){
    return new Array(len).toString().split(',').map(i=>value)
}
//方法5
function GenerateArray(len,value){
    return new Array(len).fill(value)
}
//方法6
function GenerateArray(len,value){
    return Array(len).fill(value)
}

//测试用例

//生成长度为2 值为空对象的数组
GenerateArray(2,{}) //[{},{}]
//生成长度为5 值为0的数组
GenerateArray(5,0) //[0,0,0,0,0]
//生成长度为5 值为[]的数组
GenerateArray(5,[]) //[[],[],[],[],[]]
复制代码

快速生成 值为索引递增 长度为len 的数组

function GenerateArray(len){
    return [...Array(len).keys()]
}
//测试用例
GenerateArray(10) //[0,1,2,3,4,5,6,7,8,9]
复制代码

不按索引,从1开始递增

function GenerateArray(len){
    let arr = [...Array(len+1).keys()]
    arr.splice(0,1)
    return arr
}
//测试用例
GenerateArray(10) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
复制代码

Preview 回显类

月份回显

export const previewMonth = function(i){
    return i>0&&i<13? ['一','二','三','四','五','六','七','八','九','十','十一','十二'][i-1]+'月':'Invalid month'
}
//测试用例
previewMonth(0) //Invalid month
previewMonth(1) //一月
previewMonth(2) //二月
previewMonth(3) //三月
previewMonth(4) //四月
previewMonth(5) //五月
previewMonth(6) //六月
previewMonth(7) //七月
previewMonth(8) //八月
previewMonth(9) //九月
previewMonth(10) //十月
previewMonth(11) //十一月
previewMonth(12) //十二月
previewMonth(13)//Invalid month
复制代码

星期回显

const previewWeek = function(i){
    return i>0&&i<8?'周'+['一','二','三','四','五','六','日'][i-1]:'Invalid week'
}
//测试用例
previewWeek(0) //Invalid week
previewWeek(1) //周一
previewWeek(2) //周二
previewWeek(3) //周三
previewWeek(4) //周四
previewWeek(5) //周五
previewWeek(6) //周六
previewWeek(7) //周日
previewWeek(8) //Invalid week


复制代码

时刻回显

类似发表文章的时间回显

const previewDate = function(target = Date.now()){
    /** 
     * 回显 规则:
     * {
     * <60s:'刚刚',
     * '>60s && 3600s':'x分钟之前',
     *  '>3600s && <86400s':'x小时之前',
     * '昨天':'昨天',
     * '前天':'前天',
     * '具体日期':'月日',
     * '不是当年':'显示年月日'
     * }
     * */
    // 时间格式参数 2018/07/08 06:05:59 | 2018-07-08 06:05:59 | 时间戳
    let targetStamp = parseInt(new Date(target).getTime()/1000)//参数转时间戳
    let diff = parseInt((Date.now()/1000 - targetStamp))// 计算 与当前时间相差秒数
    let dt =new Date();
    let today = dt.toLocaleDateString() //今天日期 年月日
    let yestoday = new Date(dt.setDate(dt.getDate() - 1)).toLocaleDateString()//昨天日期 年月日
    let beforeYestoday = new Date(dt.setDate(dt.getDate() - 1)).toLocaleDateString()//前天日期 年月日
    let todayDawnStamp = new Date(today +' 00:00:00').getTime()/1000 //2020/2/8
    let yestodayDawnStamp =new Date(yestoday +' 00:00:00').getTime()/1000 //昨天凌晨 时间戳 (秒)2020/2/7
    let beforeYestodayDawnStamp = new Date(beforeYestoday +' 00:00:00').getTime()/1000 //前天凌晨 时间戳(秒) 2020/2/6
    if(diff < 60) {
        return '刚刚'
    }else if(diff > 60 && diff <3600) {
        return parseInt(diff/60)+'分钟前'
    }else if(diff >= 3600 && diff < 86400){
        return parseInt(diff/3600)+'小时前'
    }else if( targetStamp < todayDawnStamp && targetStamp >= yestodayDawnStamp){
        return '昨天'
    }else if(targetStamp <= yestodayDawnStamp && targetStamp >= beforeYestodayDawnStamp){
        return '前天'
    }else if(targetStamp > beforeYestodayDawnStamp){
        let d = new Date(target);
        return (d.getMonth() +1) +'-'+ d.getDate()
    }else {
        let t = new Date(targetStamp*1000).toLocaleDateString();
        let c = new Date().getFullYear();
        return t.substr(0,4) == c?t.slice(5):t
    }
}
//测试用例
previewDate() //刚刚
previewDate('2020/3/14')   //昨天   测试日期:2020-3-15
previewDate('2020/3/13')   //前天 测试日期:2020-3-15
previewDate('2020/1/14')   // 1/14
previewDate('2019/12/14')  //2019/12/14
复制代码

转换类

JSON 转 fromData

/**
 *  JSON 转 fromData
 *  @param {Object} o 需要转成formData 的对象
 */
 const jsonToFromData = function jsonToFromData(o){
    return Object.keys(o).reduce((p, c) => !p.append(c, o[c]) && p, new FormData())
 }
 
 //测试用例
 let FromData = jsonToFromData({
    sysId:"001",
    tenantId:"002",
    userId:"003",
    username:'wuming',
    age:39,
})
FromData // FormData{}
FromData.forEach((v,k)=>{
    console.log(k,v)
})
/**输出:
 * sysId 001
 * tenantId 002
 * userId 003
 * username wuming
 * age 39
 */
复制代码

获取类

获取字符串模板内容

/**
 * 获取模板字符串里模板里的值
 * @param {String} str 模板字符串
 * @param {String} f 指定模板的左部分
 * @param {String} l 指定模板的右部分
 * @param {Number} pattern 指定模板的右部分 获取匹配内容的类型 默认1
 * @param {Number} index 结果数组的索引
 * @return any
 */
function betweenContent(str, f, l, pattern = 1, index = -1) {
    let meta = '([{}])\^$|)?*+.',
        F = meta.includes(f) ? `\\${f}` : f,
        L = meta.includes(l) ? `\\${l}` : l,
        p1 = '*?',
        p2 = '?',
        p3 = '',
        regStr = `[${F}]${pattern == 2 ? '?' : ''}([^${F + L}]+)[${L}]${pattern == 1 ? p1 : pattern == 2 ? p2 : p3}`,
        reg = new RegExp(regStr, 'gi'),
        result = pattern == 1 ? str.match(reg).map(i => i.substr(1)) : str.match(reg);
    return index == -1 ? result : result[index]
}

//测试用例

betweenContent('1[2①3]4[35②35]35[43③45]345', '[', ']')// ["2①3", "35②35", "43③45"]
betweenContent('1[2①3]4[35②35]35[43③45]345', '[', ']', 1) //["2①3", "35②35", "43③45"]
betweenContent('1[2①3]4[35②35]35[43③45]345', '[', ']', 1,1) //35②35
 
betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}') //["2①3", "35②35", "43③45"]
betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 1)//["2①3", "35②35", "43③45"]
betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 2)//["1", "{2①3}", "4", "{35②35}", "35", "{43③45}", "345"]
betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 3)//["{2①3}", "{35②35}", "{43③45}"]
betweenContent('1{2①3}4{35②35}35{43③45}345', '{', '}', 1,0)//2①3


betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-')//["2①3", "4", "35②35", "35", "43③45", "345"]
betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 1)//["2①3", "4", "35②35", "35", "43③45", "345"]
betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 2)//["1-", "2①3-", "4-", "35②35-", "35-", "43③45-", "345"]
betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 3)//["-2①3-", "-35②35-", "-43③45-"]
betweenContent('1-2①3-4-35②35-35-43③45-345', '-', '-', 3,1) //-35②35-
复制代码

获取字html字符串中的img的地址

function getImgSrc(s) {
    var r=[];
    s.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function (m,c) { r.push(c);});
    return r;
}
function getImgSrc(s) {
    let container = document.createElement('div')
    container.innerHTML = s
    return [...container.querySelectorAll('img')].map(i=>i.getAttribute('src'))   
}

//测试用例
let s=
`<p style="white-space: normal;">
<img title="" alt="1.jpg" src="https://lb.yimiyijia.cn/attached/attachment/201812/f7/71/f7f33bd36bfc80118956aaf3817d2d71.jpg_600x2000.jpg"/>
<img title="" alt="2.jpg" src="https://lb.yimiyijia.cn/attached/attachment/201812/d3/da/d3fb189830bb4654a44661ea25d374da.jpg_600x2000.jpg"/>
</p >`;

getImgSrc(s)
//输出:["https://lb.yimiyijia.cn/attached/attachment/201812…f7f33bd36bfc80118956aaf3817d2d71.jpg_600x2000.jpg", "https://lb.yimiyijia.cn/attached/attachment/201812…d3fb189830bb4654a44661ea25d374da.jpg_600x2000.jpg"]

复制代码

获取html字符串中文本内容

//非正则版
let str= '<div>岁月不饶人啊</div>'
function getHtmlText(s) {
    let container = document.createElement('div')
    container.innerHTML = s
    return  container.textContent
}
getHtmlText(str)//岁月不饶人啊
复制代码

window 相关

监听页面刷新

网页通过点击链接、地址栏输入、表单提交、脚本操作等方式加载

window.addEventListener('pageshow',function(e){
    //...
})
复制代码

扩展类

原生JS实现 Jq的data方法

Jq的data方法

$('#dom').data('id','2');//修改值
$('#dom').data('id');    //获取值
复制代码

基于Element/NodeList扩展我们自己的data方法

Element.prototype.data = function(key,value){
    if(arguments.length==2){//setter
        this.cache={
            [key]:value
        }
        return this
    }else if(arguments.length==1){//getter
        return this.cache[key]
    }   
}
NodeList.prototype.data= function(key,value){
    if(arguments.length==2){//setter
        [].forEach.call(this,function(element,index){
            element.cache={
                [key]:value
            }
            //element.data(key,value)
        })
        return this
    }else if(arguments.length==1){//getter
        return this[0].cache[key]
    }
}
复制代码

测试Code

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>原生JS实现 Jq的data方法</title>
</head>
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>
<button id="btn">我只是个按钮</button>
</body>
<script>
    let oUl = document.querySelector('ul')
    let oLis = document.querySelectorAll('li')
    let oBtn = document.getElementById('btn')
    
    oUl.data("data",{name:"wuming",age:30})
    console.log( oUl.data("data") ) //{name: "wuming", age: 30}

    oLis.data('data',[1,2,3,4])
    console.log( oLis.data("data") )//[1, 2, 3, 4]

    oBtn.data('status',true)
    console.log( oBtn.data("status") )//true
</script>
</html>
复制代码

数组 repeat 方法扩展

Array.prototype.repeat = function(n=0){
    let base = 0;
    let res= this
    while(base<n){
        res = res.concat(this)
        base++
    }
    return res
}
复制代码

测试用例:

[1,2,3].repeat() //[1,2,3]   不传参 默认是不复制 返回原数组

[1,2,3].repeat(1) //[1,2,3,1,2,3]   复制 1 遍

[1,2,3].repeat(2) //[1,2,3,1,2,3,1,2,3]   复制 2 遍

[{name:'lisi'}].repeat(1) //[{name:'lisi'},{name:'lisi'}]   复制 1 遍
复制代码

数组 findAllIndexNumber 扩展

找到数字数组中所有符合条件的索引

Array.prototype.findAllIndexNumber = function(v){
    let arr = [];
    for(let i=0;i<this.length;i++){
        if(this[i] === v){
            arr.push(i)
        }
    }
    return arr
}
复制代码

测试用例:

[1,2,3,4,1,2,1].findIndexAllNumber(1) // [0, 4, 6]
复制代码

数组 findAllIndexJson 扩展

找出 JSON数组中 和 给定的回调函数的返回值作为条件匹配到的数据的所有索引值,以数组形式返回

Array.prototype.findIndexAllJson = function(callback){
    let arr = [];
    for(let i=0;i<this.length;i++){
        if(callback(this[i])) {
            arr.push(i)
        }
    }
    return arr
}
复制代码

测试用例:

let jsonArr = [{name:'list',age:27},{name:'wangbo',age:28},{name:'zhangsan',age:27}]
jsonArr.findIndexAllJson(item=>item.age==27) // [0, 2]
复制代码

数组 substr 扩展

类似字符串的 substr

Array.prototype.substr= function(startIndex,len){
    let res = []
    for(let i=0;i<this.length;i++){
        if(i>=startIndex && res.length<len){
            res.push(this[i]) 
        }
    }
    return res
}
复制代码

测试用例:

let arr = [1,2,3,4,5] 
arr.substr(0,1) // [1]
arr.substr(0,2) // [1,2]
arr.substr(0,3) // [1,2,3]
arr.substr(1,3) // [2,3,4]
复制代码

判断(检测)类

PC还是移动端

//是否PC
function isPC(){
    return !('ontouchstart' in window)
}
//是否移动端
function isMobile(){
    return 'ontouchstart' in window
}
复制代码

原理:PC端下面的window对象,不存在 ontouchstart属性,移动端下面的window对象是有 ontouchstart属性

构造函数调用方式

如何判断一个方法的调用是new 的实例,还是构造函数的直接调用

// 方法1
function Person(name) {
    if (this.constructor===Person) {
        this.name = name;
    } else {
        throw new Error('必须使用 new 命令生成实例');  
    }
}
// 方法2
function Person(name) {
    if (new.target !== undefined) {
        this.name = name;
    } else {
        throw new Error('必须使用 new 命令生成实例');
    }
}
// 方法3
function Person(name) {
    if (new.target === Person) {
        this.name = name;
    } else {
        throw new Error('必须使用 new 命令生成实例');
    }
}
// 方法4
function Person(name) {
    if (this instanceof arguments.callee) {
        this.name = name;
    } else {
        throw new Error('必须使用 new 命令生成实例');
    }
}
// 方法5  Vue 使用此种方法
function Person(name) {
    if (this instanceof Person) {
        this.name = name;
    } else {
        throw new Error('Person is a constructor and should be called with the `new` keyword');
    }
}
let person = new Person('张三'); // 正确
let notAPerson = Person('张三');  // 报错
复制代码

new是从构造函数生成实例对象的命令。ES6为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的;

构造函数的实例上的constructor属性 指向 构造函数,因此也可以来判断 构造函数的调用方式。

数据类型检测

String

function isString(s){
    return typeof(s) === 'string'
}
function isString(s){
    return ({}).toString.call(s).slice(8,-1) === 'String'
}
复制代码

Boolean

function isBoolean(s){
    return ({}).toString.call(s).slice(8,-1) === 'Boolean'
}
function isBoolean(s){
    return s=== false || s=== true
}
复制代码

Null

function isNull(s){
    return ({}).toString.call(s).slice(8,-1) === 'Null'
}
function isNull(s){
    return s === null
}
复制代码

Undefined

function isUndefined(s){
    return ({}).toString.call(s).slice(8,-1) === 'Undefined'
}
function isUndefined(s){
    return s === undefined
}
复制代码

Number

/** 
  *第一种  通过try catch 避免 :
  * Cannot read property 'constructor' of undefined
  * Cannot read property 'constructor' of null
 */ 
function isNumber(p){
    try{
        return p.constructor === Number
    }catch(e){
        return false
    }
}
function isNumber(p){
    return typeof p === 'number'
} 

function isNumber(o){//准确  包含NaN
    return Object.prototype.toString.call(o).slice(8,-1) === 'Number'
}
复制代码

测试用例

[
    {},
    [],
    undefined,
    null,
    123,
    '123',
    Symbol('111'),
    function(){},
    new Date(),
    false,
    /\d+/gi,
    NaN
].map(item=>{
    console.log(isNumber(item))
})
//4false true 6false true
复制代码

Symbol

function isSymbol(s){
    return ({}).toString.call(s).slice(8,-1) === 'Symbol'
}
function isSymbol(s){
    return typeof s === 'symbol'
}
复制代码

Function

function isFunction(s){
    return ({}).toString.call(s).slice(8,-1) === 'Function'
}
function isFunction(s){
    return typeof s === 'function'
}
复制代码

Array

/** 
  *第一种  通过try catch 避免 :
  * Cannot read property 'constructor' of undefined
  * Cannot read property 'constructor' of null
 */ 
function isArray(o){//准确
    try{
        return o.constructor === Array
    }catch(e){
        return false
    }
}

//第二种  isArray 判断
function isArray(o){//准确
    return Array.isArray(o)
}

//第三种  isArray 判断
function isArray(o){//准确
    return o instanceof Array
}

//第四种
function isArray(o){//准确
    return Object.prototype.toString.call(o).slice(8,-1) === 'Array'
}
复制代码

测试用例

[
    {},
    [],
    undefined,
    null,
    123,
    '123',
    Symbol('111'),
    function(){},
    new Date(),
    false,
    /\d+/gi
].map(item=>{
    console.log(isArray(item))
})
// false true 9false
复制代码

Date

function isDate(s){
    return ({}).toString.call(s).slice(8,-1) === 'Date'
}
复制代码

RegExp

function isRegExp(s){
    return ({}).toString.call(s).slice(8,-1) === 'RegExp'
}
复制代码

Set

function isSet(s){
    return ({}).toString.call(s).slice(8,-1) === 'Set'
}
复制代码

Map

function isMap(s){
    return ({}).toString.call(s).slice(8,-1) === 'Map'
}
复制代码

判断严格类型

function type(o){
    return Object.prototype.toString.call(o).slice(8,-1)
}
//测试用例
let data = [
    {},
    [],
    undefined,
    null,
    123,
    '123',
    Symbol('111'),
    function(){},
    new Date(),
    false,
    /\d+/gi
]
for(let i = 0; i < data.length; i++) {
	console.log( type( data[i] ) )
}
//依次打印出:
/** 
* Object,
* Array,
* Undefined,
* Null,
* Number,
* String,
* Symbol,
* Function,
* Date,
* Boolean
* RegExp
*/
复制代码

判断对象类型

/** 
  *第一种  通过try catch 避免 :
  * Cannot read property 'constructor' of undefined
  * Cannot read property 'constructor' of null
 */ 
function isObject(o){ //准确
    try{
        return o.constructor === Object
    }catch(e){
        return false
    }
}

//第二种
function isObject(o){//准确
    return Object.prototype.toString.call(o).slice(8,-1) === 'Object'
}
复制代码

测试用例

[
    {},
    [],
    undefined,
    null,
    123,
    '123',
    Symbol('111'),
    function(){},
    new Date(),
    false,
    /\d+/gi
].map(item=>{
    console.log(isObject(item))
})
// true 10false
复制代码

判断有效数字

判断一个值是否为 有效的 数字(不包含NaN),可以是数字字符串,例如 “123"

function idValidNumber(n){
    try{
        return !isNaN(parseFloat(n)) && isFinite(n);
    }catch(e){
        return false
    }
}
复制代码

之所以加上 try catch,是因为 针对 Symbol 值使用此方法会报错:Uncaught TypeError: Cannot convert a Symbol value to a string,用try catch 规避

测试用例

[
    {},
    [],
    undefined,
    null,
    123,
    '123',
    Symbol('111'),
    function(){},
    new Date(),
    false,
    /\d+/gi,
    NaN
].map(item=>{
    console.log(idValidNumber(item))
})
//4false 2true 6false
复制代码

判断空对象

function isEmptyObject(o){
    return ({}).toString.call(o).slice(8,-1) === "Object" &&  !Object.keys(o).length
}
复制代码

条件1:传入的参数首先得是一个对象;条件2:传入的参数对象身上没有 key;同时满足为true ,其他为false

测试用例

[
	{},
	[],
	function(){},
	new Date(),
	/\d+/g,
	null,
	undefined,
	'',
	'123',
	Symbol('sdsd'),
	false,
	true,
	123,
	NaN,
	1,
	0,
	{a:1}
].map(item=>{
    console.log(isEmptyObject(item))
})
// true 16false
复制代码

判断空数组

function isEmptyArray(o){
  	return Array.isArray(o) && !o.length      
}
复制代码

条件1:传入参数确实是数组;条件2:数组长度确实为0;同时满足为 true,其他为 false

测试用例

[
{},
[],
function(){},
new Date(),
/\d+/g,
null,
undefined,
'',
'123',
Symbol('sdsd'),
false,
true,
123,
NaN,
1,
0,
{a:1}
].map(item=>{
    console.log(isEmptyArray(item))
})
//false true 15false
复制代码

判断对象key存在与否

//1.检测传入的第一个参数是否是对象
//2.传入的第二个参数是否是字符串
//3.检测这个字符串是否属于这个对象的key
let obj = {
    a:0,
    b:1,
    c:undefined,
    d:null,
    e:[],
    f:'',
    j:NaN,
    h:{}
}
 function hasProp(obj,key){
    if(({}).toString.call(obj).slice(8,-1) !== "Object"){
        throw Error(`传入的 ${obj} 不是一个有效对象`)
    }
    if(typeof key !== 'string'){
        throw Error(`传入的key ${key} 必须是一个字符串,但是你传入的类型是 ${typeof(key)}`)
    }
    return obj.hasOwnProperty( key )
}
// obj.hasOwnProperty( key )
// key in obj
复制代码

obj.hasOwnProperty( key )key in obj都是可以的

统计类

数组的纵向统计

//示例:
let arr = [
    [1, 2, 3, 4, 5],
    [1, 2, 3, 4, 5],
    [1, 2, 3, 4, 5],                
    [1, 2, 3, 4, 5],
    [1, 2, 3, 4, 5],
]
//  [5, 10, 15, 20, 25]
复制代码

code:

function longitudinalStatistics(arr){
    let r = new Array(arr[0].length).toString().split(',').fill(0)
    for(let i=0; i<arr.length; i++) {
        for(let j=0; j<arr[i].length; j++) {
            resArr[j] += arr[i][j]
        }
    }
    return resArr
}
longitudinalStatistics(arr)//[5, 10, 15, 20, 25]
复制代码

数组的横向统计

//示例
let arr = [
    [1,2,3,4,5],// =>1+2+3+4+5= 15
    [1,2,3,4,5],// =>1+2+3+4+5= 15
    [1,2,3,4,5],// =>1+2+3+4+5= 15                      ==>  [15, 15, 15, 15, 15]
    [1,2,3,4,5],// =>1+2+3+4+5= 15
    [1,2,3,4,5],// =>1+2+3+4+5= 15
]
复制代码

code

function horizontalStatistics(arr){
    return arr.map(i=>i.reduce((p,c)=>p+c))
}
horizontalStatistics(arr) // [15, 15, 15, 15, 15]
复制代码

工具类

深度合并两个对象

function merge(f, s) {
    for (var i in s) {
        f[i] = f[i] && f[i].toString() === "[object Object]"?merge(f[i], s[i]) : f[i] = s[i];
    }
    return f;
}
复制代码

测试用例

var a = {text:'text',chidren:"chidren",c:{d:1,f:{t:1,m:{o:22}}}}
var b = {text:'title',chidren:"list",c:{d:9,g:33,f:{y:88,m:{l:3}}}}
merge(a, b)//{text:'title',chidren:"list",c:{d:9,g:33,f:{t:1,y:88,m:{o:22,l:3}}}
复制代码

深度合并多个对象

const MergeMultiple = function(...a){
    //参数长度
    let l = a.length
    //没有传参 抛出错误
    if(l==0) throw Error('Pass at least one object parameter')
    //参数传一个 直接返回这个
    if(l==1)return a[0]
    //深度合并两个对象策略
    let m = function(f, s) {
        for (let i in s) {
            f[i] = f[i] && f[i].toString() === "[object Object]"?m(f[i], s[i]) : f[i] = s[i]
        }
        return f
    }
    //参数传一个 直接返回合并后的对象
    if(l==2)return m(a[0],a[1])
    //参数大于2,则执行递归合并,并在长度为2时,返回合并对象
    while(a.length>2){
        a.splice(0,2,m(a[0],a[1]))
        if(a.length==2)return m(a[0],a[1])
    }
}
复制代码

测试用例

MergeMultiple({name:'rookie',age:30,job:'web'})
//{name: "rookie", age: 30, job: "web"}
MergeMultiple({name:'rookie',age:30,job:'web',info:{sex:'men'}},{info:{sex:'women',country:'china'}})
//{name: "rookie", age: 30, job: "web",info: {sex: "women", country: "china"}}
MergeMultiple({info:{sex:'men'}},{info:{sex:'women',country:'china'}},{feature:{height:'172cm'}},{feature:{weight:'65kg'}})
//{info: {sex: "women", country: "china"},feature: {height: "172cm", weight: "65kg"}}
复制代码

精度丢失处理

加减乘除 中的精度丢失处理方法

/**
 * 计算方法 calc
 * @param { number } type :0 加  1 减 2 乘 3 除
 * @param { String | Number } a :计算数a
 * @param { String | Number } b :计算数b
 * @param { Number } digit  :结果保留的位数
 * @return Number | String
 */
function calc(type,a,b,digit){
    let r1, r2;
    try { r1 = a.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = b.toString().split(".")[1].length } catch (e) { r2 = 0 }
    let maxLen = Math.pow(10, Math.max(r1, r2))
    let tyeps= [
        (Math.round(maxLen*a) + Math.round(maxLen*b))/maxLen,//加
        (Math.round(maxLen*a) - Math.round(maxLen*b))/maxLen,//减
        (Math.round(maxLen*a) * Math.round(maxLen*b))/(maxLen*maxLen),//乘
        Math.round(maxLen*a)/Math.round(maxLen*b)//除
    ]
    let round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)
    let str = String(round(tyeps[type],digit))
    if(digit){
        if(str.includes('.'))return str.split('.')[0]+'.'+str.split('.')[1].padEnd(digit,0)
        return (str+'.').padEnd((str+'.').length+digit,0)
    }else{
        return tyeps[type]
    }
}
复制代码

测试用例:type:0 加法

/**
 *
 *加法(精度丢失问题) type:0
 *
 */

//1.1 加法 - 小数相加 保留位数
console.log(calc(0,0.1,0.2))     //0.3
console.log(calc(0,0.1,0.2,0))   //0.3
console.log(calc(0,0.1,0.2,1))   //0.3
console.log(calc(0,0.1,0.2,2))   //0.30
console.log(calc(0,0.1,0.2,3))   //0.300

//1.2 加法 - 整数相加 保留位数
console.log(calc(0,10,90))     //100
console.log(calc(0,10,90,0))   //100
console.log(calc(0,10,90,1))   //100.0
console.log(calc(0,10,90,2))   //100.00

//1.3 加法 - 整数和小数相加 保留位数
console.log(calc(0,10.05,90))     //100.05
console.log(calc(0,10.15,90,0))   //100.15
console.log(calc(0,10.25,90,1))   //100.3
console.log(calc(0,10.35,90,2))   //100.35
console.log(calc(0,10.45,90,0))   //100.45
console.log(calc(0,10.55,90,2))   //100.55
console.log(calc(0,10.65,90,1))   //100.7
复制代码

测试用例:type:1 减法

/**
 *
 *减法(精度丢失问题) type:1
 *
 */

//1.1 减法 - 小数相减 保留位数
console.log(calc(1,0.1,0.3))     //-0.2
console.log(calc(1,0.1,0.3,0))   //-0.2
console.log(calc(1,0.1,0.3,1))   //-0.2
console.log(calc(1,0.1,0.3,2))   //-0.20
console.log(calc(1,0.1,0.3,3))   //-0.200

//1.2 减法 - 整数相减 保留位数
console.log(calc(1,10,90))     //-80
console.log(calc(1,100,90,0))  // 10
console.log(calc(1,10,90,1))   //-80.0
console.log(calc(1,10,90,2))   //-80.00

//1.3 减法 - 整数和小数相减 保留位数
console.log(calc(1,10.05,90))     //-79.95
console.log(calc(1,10.15,90,0))   //-79.85
console.log(calc(1,10.25,90,1))   //-79.7
console.log(calc(1,10.35,90,2))   //-79.65
console.log(calc(1,10.45,90,0))   //-79.55
console.log(calc(1,10.55,90,2))   //-79.45
console.log(calc(1,10.65,90,1))   //-79.3
复制代码

测试用例:type:2 乘法

/**
 *
 *乘法(精度丢失问题) type:2
 *
 */

//1.1 乘法 - 小数相乘 保留位数
console.log(calc(2,0.1,0.1))     //0.01
console.log(calc(2,0.3,0.5698))  //0.17094
console.log(calc(2,0.3,0.5698,1))  //0.2
console.log(calc(2,0.3,0.5698,2))  //0.17
console.log(calc(2,0.3,0.5698,3))  //0.171


//1.2 乘法 - 整数相乘 保留位数
console.log(calc(2,10,90))     //900
console.log(calc(2,100,90,0))  //9000
console.log(calc(2,10,90,1))   //900.0
console.log(calc(2,10,90,2))   //900.00

//1.3 乘法 - 整数和小数相乘 保留位数
console.log(calc(2,10.05,90,2))   //904.50
console.log(calc(2,10.15,90,0))   //913.5
console.log(calc(2,10.25,90,1))   //922.5
console.log(calc(2,10.35,90,2))   //931.50
console.log(calc(2,10.45,90,0))   //940.5
console.log(calc(2,10.55,90,2))   //949.50
console.log(calc(2,10.65,90,1))   //958.5
复制代码

测试用例:type:3 除法

/**
 *
 *除法(精度丢失问题) type:3
 * PS:有 无限循环小数 情况
 */

//1.1 除法 - 小数相除 保留位数
console.log(calc(3,0.1,0.3))       //0.3333333333333333  
console.log(calc(3,0.1,0.3,1))     //0.3
console.log(calc(3,0.1,0.3,2))     //0.33
console.log(calc(3,0.3,0.5698))    //0.5265005265005265
console.log(calc(3,0.3,0.5698,1))  //0.5
console.log(calc(3,0.3,0.5698,2))  //0.53
console.log(calc(3,0.3,0.5698,3))  //0.527


//1.2 除法 - 整数相除 保留位数
console.log(calc(3,10,90))     //0.1111111111111111
console.log(calc(3,100,90,0))  //1.1111111111111112
console.log(calc(3,10,90,1))   //0.1
console.log(calc(3,10,90,2))   //0.11

//1.3 除法 - 整数和小数相除 保留位数
console.log(calc(3,10.05,90,2))   //0.11
console.log(calc(3,10.15,90,0))   //0.11277777777777778
console.log(calc(3,10.25,90,1))   //0.1
console.log(calc(3,10.35,90,2))   //0.12
console.log(calc(3,10.45,90,0))   //0.11611111111111111
console.log(calc(3,10.55,90,2))   //0.12
console.log(calc(3,10.65,90,1))   //0.1
复制代码

其他类

交换两个变量值的位置


var a = {a:1}
var b = {b:2}

a = [b,b=a][0]

a// {b: 2}
b// {a: 1}

复制代码

结语

上面的方法大部分是自己总结,一部分参考了其他大佬的思想加以实现,在此,感谢大神们的总结。如果对你有帮助,顺手点个赞

如果你有更好的点子,或者没有找到你想要的工具函数,欢迎留言

文中若有不准确或错误的地方,欢迎指出