这些JS工具函数够你用到2020年底了

前言

活不多说,自己平时搜集的干货函数奉上。
干货函数
视频全屏

      // 全屏
      function fullScreen(el) {
        const isFullscreen =
          document.fullScreen ||
          document.mozFullScreen ||
          document.webkitIsFullScreen;
        if (!isFullscreen) {
          //进入全屏,多重短路表达式
          (el.requestFullscreen && el.requestFullscreen()) ||
            (el.mozRequestFullScreen && el.mozRequestFullScreen()) ||
            (el.webkitRequestFullscreen && el.webkitRequestFullscreen()) ||
            (el.msRequestFullscreen && el.msRequestFullscreen());
        } else {
          //退出全屏,三目运算符
          document.exitFullscreen
            ? document.exitFullscreen()
            : document.mozCancelFullScreen
            ? document.mozCancelFullScreen()
            : document.webkitExitFullscreen
            ? document.webkitExitFullscreen()
            : "";
        }
      }


找出数字在数组中下一个相邻的元素

let i = "";
let rr = [];

const name = (n, arr1)=>{
    let num = Number(n);
    for (let i = 0; i < arr1.length; i++) {
        const element = arr1[i];
        if (element != num) {
            rr.push(num--);
        }
    }
    return rr.find((el) => {
        let newel = String(el);
        return arr1.includes(newel);
    })}

let arr = ["2", "4", "6", "8", "10", "12", "14", "16", "18", "20", "22", "24", "27", "30", "33", "36", "42", "48", "54", "60"]
console.log(name('5',arr)); //4


格式化时间

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = parseInt(time) * 1000
  } else {
    time = +time
  }
  const d = new Date(time)
  const now = Date.now()

  const diff = (now - d) / 1000

  if (diff < 30) {
    return '刚刚'
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
  }
  if (option) {
    return parseTime(time, option)
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      d.getDate() +
      '日' +
      d.getHours() +
      '时' +
      d.getMinutes() +
      '分'
    )
  }
}


解析时间

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
function parseTime(time, cFormat) {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string')) {
      if ((/^[0-9]+$/.test(time))) {
        // support "1548221490638"
        time = parseInt(time)
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        time = time.replace(new RegExp(/-/gm), '/')
      }
    }

    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
    return value.toString().padStart(2, '0')
  })
  return time_str
}


解析Url地址

/**
 * @param {string} url
 * @returns {Object}
 */
function param2Obj(url) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
  if (!search) {
    return {}
  }
  const obj = {}
  const searchArr = search.split('&')
  searchArr.forEach(v => {
    const index = v.indexOf('=')
    if (index !== -1) {
      const name = v.substring(0, index)
      const val = v.substring(index + 1, v.length)
      obj[name] = val
    }
  })
  return obj
}


合并两个对象

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
function objectMerge(target, source) {
  if (typeof target !== 'object') {
    target = {}
  }
  if (Array.isArray(source)) {
    return source.slice()
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property]
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty)
    } else {
      target[property] = sourceProperty
    }
  })
  return target
}


数组去重

/**
 * @param {Array} arr
 * @returns {Array}
 */
function uniqueArr(arr) {
  return Array.from(new Set(arr))
}


防抖

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}


简易搜索

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="text" id="int">
</body>
<script>
  let list = ["示例1","示例12","示例5","示例56"];
  document.querySelector('#int').onchange=function(e){
    console.log(search(e.target.value));
  }
 
  function search(val) {
    if (val) {
        return list.filter(function (item) {
          return Object.keys(item).some(function (key) {
            return String(item[key]).toLowerCase().indexOf(val) > -1
          })
        })
    }
    return list
  }

</script>
</html>


将秒化为时分秒

function formateSeconds (endTime) {
      let secondTime = parseInt(endTime); //将传入的秒的值转化为Number
      let min = 0; // 初始化分
      let h = 0; // 初始化小时
      let result = "";
      if (secondTime > 60) {
        //如果秒数大于60,将秒数转换成整数
        min = parseInt(secondTime / 60); //获取分钟,除以60取整数,得到整数分钟
        secondTime = parseInt(secondTime % 60); //获取秒数,秒数取佘,得到整数秒数
        if (min > 60) {
          //如果分钟大于60,将分钟转换成小时
          h = parseInt(min / 60); //获取小时,获取分钟除以60,得到整数小时
          min = parseInt(min % 60); //获取小时后取佘的分,获取分钟除以60取佘的分
        }
      }
      result = `${h.toString().padStart(2, "0")}:${min.toString().padStart(2, "0")}:${secondTime.toString().padStart(2, "0")}`;
      return result;
    }
    


将时分秒化为秒

function formSeconds (times) {
        let arr = times.split(":");
        let s = arr[2];
        let m = arr[1];
        let h = arr[0];
        let m1 = m<10?m.replace(/\b(0+)/gi,""):m;
        let h1 = h<10?h.replace(/\b(0+)/gi,""):h;
        return m1*60+Number(h1)+Number(s)
}


对象深层遍历

var obj = {
        a:{
            b:{
                c:"maomin"
            }
        }
    }
const safeGet = (obj, path) => {
        try {
          return path.split('.').reduce((o, k) => o[k], obj)
        } catch (e) {
          return undefined
        }
    }
console.log(safeGet(obj,'a.b.c'));// maomin


带有分割符的字符串转化成一个n维数组

 var str = "A-2-12";
 var str1 = str.split('-');
 var arr = str1.reverse().reduce((pre,cur,i) => {
 if(i==0)
  { pre.push(cur)
   return pre
 }
  return [cur,pre]
},[])
console.log(arr) // ["A"["B",["C"]]]



获取时间戳

  function thedata(d){
      return d.replace(/\-/g, "\/")
  }
  var serverTime = parseInt(new Date(thedata('2020-08-12 15:52:11')).valueOf());
  console.log(serverTime); // 1597218731000,获取到时间戳



对象深拷贝

function deepClone(target) {
    // 定义一个变量
    let result;
    // 如果当前需要深拷贝的是一个对象的话
    if (typeof target === 'object') {
    // 如果是一个数组的话
        if (Array.isArray(target)) {
            result = []; // 将result赋值为一个数组,并且执行遍历
            for (let i in target) {
                // 递归克隆数组中的每一项
                result.push(deepClone(target[i]))
            }
         // 判断如果当前的值是null的话;直接赋值为null
        } else if(target===null) {
            result = null;
         // 判断如果当前的值是一个RegExp对象的话,直接赋值    
        } else if(target.constructor===RegExp){
            result = target;
        }else {
         // 否则是普通对象,直接for in循环,递归赋值对象的所有值
            result = {};
            for (let i in target) {
                result[i] = deepClone(target[i]);
            }
        }
     // 如果不是对象的话,就是基本数据类型,那么直接赋值
    } else {
        result = target;
    }
     // 返回最终结果
    return result;
}



简易版对象拷贝

 function copy(obj) {
    if(typeof obj == "object") { //判断是否复杂类型
       var result = obj.constructor == Array ? [] : {};//判断数组类型或是object,数组即result=[],object即result={}
        for(let i in obj) {
            result[i] = typeof obj[i] == "object" ? copy(obj[i]) : obj[i]//判断数据每一项是否是object
        }
    } else {
        var result = obj //基本类型直接拷贝
    }
  return result;
}



实现一个模板引擎

function render(template, data) {
  const reg = /\{\{(\w+)\}\}/; // 模板字符串正则
  if (reg.test(template)) { // 判断模板里是否有模板字符串
    const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段
    template = template.replace(reg, data[name]); // 将第一个模板字符串渲染
    return render(template, data); // 递归的渲染并返回渲染后的结构
  }
  return template; // 如果模板没有模板字符串直接返回
}
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
  name: '姓名',
  age: 18
}
render(template, data); // 我是姓名,年龄18,性别undefined



节流

// ①定时器实现
const throttle = (fn,delay = 500) =>{
  let flag = true;
  return (...args) => {
    if(!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(this,args);
      flag = true;
    },delay);
  };
}
// ②时间戳实现
const throttle = (fn,delay = 500) => {
  let preTime = Date.now();
  return (...args) => {
    const nowTime = Date.now();
    if(nowTime - preTime >= delay){
          preTime = Date.now();
          fn.apply(this,args);
    }
  }
}



封装fetch

/**
 * 封装fetch函数,用Promise做回调
 * @type {{get: (function(*=)), post: (function(*=, *=))}}
 */
const fetchUtil = {
    get: (url) => {
        return new Promise((resolve, reject) => {
            fetch(url, {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                }
            }).then((response) => response.json()).then(response => {
                resolve(response);
            }).catch(err => {
                reject(new Error(err));
            });
        });
    },
    post: (url, params) => {
        return new Promise((resolve, reject) => {
            fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                body: params
            }).then((response) => response.json()).then(response => {
                resolve(response);
            }).catch(err => {
                reject(new Error(err));
            });
        });
    }
};



判断浏览器环境

function getSystem(){
    const mac = /mac/i,
        linux = /linux/i,
        win = /win/i;
    const platform = navigator.platform.toLowerCase();
    if(mac.test(platform)){
        return 'MAC';
    } else if(win.test(platform)){
        return 'WIN';
    } else if(linux.test(platform)){
        return 'Linux';
    }
    return undefined;
}
const browser = {
    versions:function(){
        let ret = 'xxSys';
        const u = navigator.userAgent;
        const isMobile = !!u.match(/AppleWebKit.*Mobile.*/),
            ios = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),
            android = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
        if(isMobile){
            if(ios) return 'IOS';
            if(android) return 'Android';
        } else {
            ret = getSystem() || ret;
        }
        return ret;
    }(),
};



定义数组内部对象形式

const objArrtransArr = (olddata, oldval, oldname)=>{
    const newArr = [];
    olddata.forEach(item => {
        // 定义数组内部对象形式
        let obj = {};
        obj.value = item[oldval];
        obj.name = item[oldname];
        // 将对象数据推到数组中
        newArr.push(obj);
    });
    return newArr;
}



解析html字符串

function (htmlobj) {
          var el = document.createElement('div');
          el.innerHTML = htmlobj;
          var tags = el.getElementsByTagName('img');
          var text = tags[0].getAttribute("src");
          return text;
}



判断浏览器是否支持摄像头

function videoCheck () {
      var deviceList = [];
      navigator.mediaDevices
        .enumerateDevices()
        .then(devices => {
          devices.forEach(device => {
            deviceList.push(device.kind);
          });
          if (deviceList.indexOf("videoinput") == "-1") {
            console.info("没有摄像头");
            return false;
          } else {
            console.info("有摄像头");
          }
        })
        .catch(function(err) {
          alert(err.name + ": " + err.message);
        });
    }


回文算法

  //忽略标点符号、大小写和空格,正着读和反着读一模一样。
function made(str) {
        var str1 = str.toLowerCase(); //先将字符串全部转换为小写
        var reg = /[\W\_]/g; // 删除所有非字母数字字符和下划线
        var str2 = str1.replace(reg, ""); // 去掉非字母和非数字
        var str3 = str2.split(""); // 字符串分隔成数组
        var str4 = str3.reverse(); // 反转数组中的元素
        var str5 = str4.join(""); // 反转后的数组转化为字符串
        return str2 === str5;
}



    持续更新…

结语

        欢迎关注我的公众号前端历劫之路
        回复关键词电子书,即可获取12本前端热门电子书。
        回复关键词红宝书第4版,即可获取最新《JavaScript高级程序设计》(第四版)电子书。
        关注公众号后,点击下方菜单即可加我微信,我拉拢了很多IT大佬,创建了一个技术交流、文章分享群,期待你的加入。

作者:Vam的金豆之路

主要领域:前端开发

我的微信:maomin9761

微信公众号:前端历劫之路