常用的js工具函数

对象属性剔除
应用场景很简单,当你需要使用一个对象,但想移除部分属性时,可以使用该方法。同样的,
你可以实现一个对象属性选取方法。

 function omit(object, props = []) {
    let res = {};
    Object.keys(object).forEach((key) => {
      if (props.includes(key) === false) {
        res[key] =
          typeof object[key] === "object" && object[key] !== null
            ? JSON.parse(JSON.stringify(object[key]))
            : object[key];
      }
    });
    return res;
  }

  let data = {
    id: 1,
    title: "xxx",
    comment: [],
  };
  console.log(omit(data, ["id"])); // => {title: "xxx", comment: []}
  console.log(omit(data, ["id", "comment"])); // => {title: "xxx"}
对象属性的筛选:
返回的data是对象时 后端返回的数据中有些属性是不需要显示在页面上,此时需要进行筛选出需要用到的属性

function
chooseField(object, props = []) { let res = {}; var tempArr = Object.keys(object); props.forEach((key) => { if (tempArr.includes(key) === true) { res[key] = typeof object[key] === "object" && object[key] !== null ? JSON.parse(JSON.stringify(object[key])) : object[key]; } else { res[key] = ""; } }); return res; } let data = { a: 1, b: "xxx", c: [], d() {}, e: "", f: 0, g: null, h: undefined, i: NaN, j: false, };
  console.log(chooseField(data, ["a", "c", "d", "e", "i", "z"])); // => {a: 1, c: Array(0), e: "", i: NaN, d: ƒ, z: ""}
返回的data是对象时 后端返回的数据中有些属性是不需要显示在页面上,此时需要进行筛选出需要用到的属性 且 还可以调整部分字段名, 没返回需要的字段时还可以指定用什么数据占位
 
  // 参数1: 原对象数据
  // 参数2: 从原对象选出需要的字段名
  // 参数3: 原字段名修改后的字段名
  // 参数4: 选出来的原字段名不存在时 用该数据占位
  function chooseField(object, props_l = [], props_c = {}, props_r = {}) {
    let retObj = {};
    let dataArr = Object.keys(object);
    let modeifyArr = Object.keys(props_c);
    // 说明含有需要调整的字段名
    if (Object.keys(props_c).length > 0) {
      props_l.forEach((item, index) => {
        if (dataArr.includes(item) === true) {
          if (modeifyArr.includes(item)) {
            retObj[props_c[item]] =
              typeof object[item] === "object" && object[item] != null
                ? JSON.parse(JSON.stringify(object[item]))
                : object[item];
          } else {
            retObj[item] =
              typeof object[item] === "object" && object[item] != null
                ? JSON.parse(JSON.stringify(object[item]))
                : object[item];
          }
        } else {
          // 返回数据缺少需要的字段
          if (modeifyArr.includes(item)) {
            retObj[props_c[item]] = props_r[props_c[item]];
          } else {
            retObj[item] = props_r[item];
          }
        }
      });
    } else {
      // 说明没有需要调整的字段名
      props_l.forEach((item, index) => {
        if (dataArr.includes(item) === true) {
          retObj[item] =
            typeof object[item] === "object" && object[item] != null
              ? JSON.parse(JSON.stringify(object[item]))
              : object[item];
        } else {
          // 返回数据缺少需要的字段
          retObj[item] = props_r[item];
        }
      });
    }
    return retObj;
  }

  let data = {
    a_: 1111,
    // b_: "xxx",
    c: ["aaaaa"],
    e: "hello",
    f: 0,
    g: null,
    h: undefined,
    i: NaN,
    j: false,
  };
  // 参数1: 后端返回的数据
  // 参数2: 前端需要用到的数据
  // 参数3: 如果传了该参数说明含有需要调整的字段名, 否则不含有调整的字段名
  // 参数4: 返回数据对象没有该字段时 传递要用什么占位 比如用""、{}、[]、null等
  var ret1 = chooseField(
    data,
    ["a_", "b_", "c", "d_", "e", "i", "z_"],
    { a_: "a", b_: "b", d_: "d", z_: "z" },
    { a: 0, b: "bbbb", c: [], d: null, e: "", i: "", z: {} }
  );
  console.log(ret1); // => {a: 1111, b: "bbbb", c: ["aaaaa"], d: null, e: "hello", i: NaN, z: {}}

  var ret2 = chooseField(
    data,
    ["a_", "b", "c", "d", "e", "i", "z", "zz"],
    {},
    {
      a_: 0,
      b: "bbbb",
      c: [],
      d: null,
      e: "",
      i: "",
      z: { name: "zzzz" },
      zz: [],
    }
  );
  console.log(ret2); // => {a_: 1111, b: "bbbb", c: ["aaaaa"], d: null, e: "hello", i: NaN, z: { name: 'zzzz' }, zz: []}

  /*
  第四个参数解释 解释:
  当没有a属性时用 0 占位
  当没有b属性时用 "" 占位
  当没有c属性时用 [] 占位
  当没有d属性时用 null 占位
  当没有e属性时用 "" 占位
  当没有i属性时用 "" 占位
  当没有z属性时用 {} 占位
  */

  /*
    假如我觉得只有个别属性可能没有返回
    比如我觉得 d 和 z属性可能没返回
    而且如果一旦 d 有数据时 是字符串 此时可以 用 '' 占位
    一旦 z 有数据时 是对象 此时可以 用 {} 占位
  */
  var ret_ = chooseField(
    data,
    ["a_", "b_", "c", "d", "e", "i", "z"],
    { b_: "b" },
    { a_: "", b: "", c: "", d: "", e: "", i: "", z: {} }
  );
  console.log(ret_); // => {a_: 1111, b: "", c: ["aaaaa"], d: "", e: "hello", i: NaN, z: {}}

 

返回的data是数组时且部分字段名不是前端想要的 此时需要转换成前端想要的字段名 返回含有部分字段的数组

 function transField(array, props_ = [], props = []) {
    return array.map((obj) => {
      let tempObj = {};
      let tempFields = Object.keys(obj);
      props.forEach((item_, index) => {
        if (tempFields.includes(props_[index]) === true) {
          tempObj[item_] =
            typeof obj[props_[index]] === "object" && obj[props_[index]] != null
              ? JSON.parse(JSON.stringify(obj[props_[index]]))
              : obj[props_[index]];
        } else {
          tempObj[item_] = "";
        }
      });
      return tempObj;
    });
  }

  let data = [
    { name_: "a", age_: { aaaa: "1111" }, hobbit_: "吃", value_: "值" },
    { name_: "a_", age_: 11, hobbit_: "吃_", value_: null },
    { name_: "a_", age_: 11, hobbit_: "吃_" },
  ];
  // 参数1: 后端返回到的数据 参数2: 后端返回数据的字段名, 参数3: 前端需要的属性名
  console.log(
    transField(
      data,
      ["name_", "age_", "value_"],
      ["name", "age", "value", "aa"]
    )
  ); // => [{name: "a", age: {aaaa: "1111"}, value: "值", aa: ""}, {name: "a_", age: 11, value: null, aa: ""}, {name: "a_", age: 11, value: "", aa: ""}]
返回的data是数组时且只需要用到部分字段时且不需要修改属性名
 function getField(array, props = []) {
    return array.map((item) => {
      let tempObj = {};
      let tempFields = Object.keys(item);
      props.forEach((item_, index) => {
        if (tempFields.includes(item_) === true) {
          tempObj[item_] =
            typeof item[item_] === "object" && item[item_] != null
              ? JSON.parse(JSON.stringify(item[item_]))
              : item[item_];
        } else {
          tempObj[item_] = "";
        }
      });
      return tempObj;
    });
  }

  let data = [
    { name_: "a", age_: { aaaa: "111" }, hobbit_: "吃", value_: "值" },
    { name_: "a_", age_: 11, hobbit_: "吃_", value_: null },
    { name_: "a_", age_: 11, hobbit_: "吃_" },
  ];
  console.log(getField(data, ["name_", "age_", "value_", "aa"])); // => [{name_: "a", age_: {aaaa: "111"}, value_: "值", aa: ""}, {name_: "a_", age_: 11, value_: null, aa: ""}, {name_: "a_", age_: 11, value_: "", aa: ""}]

日期格式化
一个很灵活的日期格式化函数,可以根据使用者给定的格式进行格式化,能应对大部分场景。

  /**
   * @param {string} format
   * @param {number} timestamp - 时间戳
   * @return {string}
   */
  function formatDate(format = "Y-M-D h:m:s", timestamp = Date.now()) {
    let date = new Date(timestamp);
    let dateInfo = {
      Y: date.getFullYear(),
      M: date.getMonth() + 1,
      D: date.getDate(),
      h: date.getHours(),
      m: date.getMinutes(),
      s: date.getSeconds(),
    };
    let formatNumber = (n) => (n >= 10 ? n : "0" + n);
    let res = format
      .replace("Y", dateInfo.Y)
      .replace("M", formatNumber(dateInfo.M))
      .replace("D", formatNumber(dateInfo.D))
      .replace("h", formatNumber(dateInfo.h))
      .replace("m", formatNumber(dateInfo.m))
      .replace("s", formatNumber(dateInfo.s));
    return res;
  }
  console.log(formatDate()); // => 2021-07-23 10:56:01
  console.log(formatDate("Y年M月D日 h:m:s")); // => 2021年07月23日 10:56:41
  console.log(formatDate("Y年M月D日 h:m")); // => 2021年07月23日 10:57
  console.log(formatDate("M月D日 h:m")); // =>07月23日 11:00
  console.log(formatDate("h:m Y-M-D", 1627009064020)); // => 10:57 2021-07-23
  console.log(formatDate("h:m Y/M/D", 1627009064020)); // => 10:57 2021/07/23

 

性能分析
Web Performance API允许网页访问某些函数来测量网页和Web应用程序的性能。
performance.timing包含延迟相关的性能信息。
performance.memory包含内存信息,是Chrome中添加的一-个非标准扩展,在使用时需要注
意。

window.onload = function () {
    setTimeout(() => {
      let t = performance.timing,
        m = performance.memory;
      console.table({
        DNS查询耗时:
          (t.domainLookupEnd - t.domainLookupStart).toFixed(0) + "ms",
        TCP链接耗时: (t.connectEnd - t.connectStart).toFixed(0) + "ms",
        request请求耗时: (t.responseEnd - t.responseStart).toFixed(0) + "ms",
        解析dom树耗时: (t.domComplete - t.domInteractive).toFixed(0) + "ms",
        白屏时间: (t.responseStart - t.navigationStart).toFixed(0) + "ms",
        domready时间:
          (t.domContentLoadedEventEnd - t.navigationStart).toFixed(0) + "ms",
        onload时间: (t.loadEventEnd - t.navigationStart).toFixed(0) + "ms",
        js内存使用占比: m
          ? ((m.usedjsHeapSize / m.totaljsHeapSize) * 100).toFixed(2) + "%"
          : undefined,
      });
    });
  };

 

防抖
性能优化方案,防抖用于减少函数请求次数,对于频繁的请求,只执行这些请求的最后一次。
基础版本

function debounce(func, wait = 300) {
    let timer = null;
    return function () {
      if (timer !== null) {
        clearTimeout(timer);
      }
      timer = setTimeout(func, wait);
    };
  }
  let scrollHandler = debounce(() => {
    console.log("等待300ms后发送了ajax请求。。。");
  }, 300);
  scrollHandler();

改进版本添加是否立即执行的参数,因为有些场景下,我们希望函数能立即执行。

/**
   * @param {function} func - 执行函数
   * @param {number} wait - 等待时间
   * @param {boolean} immediate - 是否立即执行
   * @return {function}
   */

  function debounce(func, wait = 300, immediate = false) {
    let timer, ctx;
    let later = (arg) =>
      setTimeout(() => {
        func.apply(ctx, arg);
        timer = ctx = null;
      }, wait);
    return function (...arg) {
      if (!timer) {
        timer = later(arg);
        ctx = this;
        if (immediate) {
          func.apply(ctx, arg);
        }
      } else {
        clearTimeout(timer);
        timer = later(arg);
      }
    };
  }

使用

let scrollHandler = debounce(function (e) {
    console.log(e);
  }, 500);
  window.onscroll = scrollHandler;

节流
性能优化方案,节流用于减少函数请求次数,与防抖不同,节流是在一段时间执行一次、一段时间执行一次。

 

/**
   * @param {function} func - 执行函数
   * @param {number} delay - 延迟时间
   * @return {function}
   */
  function throttle(func, delay) {
    let timer = null;
    return function (...arg) {
      if (!timer) {
        timer = setTimeout(() => {
          func.apply(this, arg);
          timer = null;
        }, delay);
      }
    };
  }

使用

let scrollHandler = throttle(function (e) {
    console.log(e);
  }, 500);
  window.onscroll = scrollHandler;

 设置cookie

function setCookie(name, value, iDay)
{
  var oDate=new Date();
  oDate.setDate(oDate.getDate()+iDay);
  document.cookie=name+'='+value+';expires='+oDate;
}

setCookie('token', 111, 30); // 设置token 30天后过期

读取cookies

function getCookie(name)
{
  var arr=document.cookie.split('; ');
  for(var i=0;i<arr.length;i++)
  {
    var arr2=arr[i].split('=');
    if(arr2[0]==name)
    {
      return arr2[1];
    }
  }
  return '';
}
getCookie('token') // => "111"

删除cookies 

function removeCookie(name)
{
  setCookie(name, 1, -1);
}

 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;
}
// console.log(GetUrlParam()) ?a=1&b=2&c=3 ==> {a: "1", b: "2", c: "3"}

 禁止右键、选择、复制

['contextmenu', 'selectstart', 'copy'].forEach(function(ev){
  document.addEventListener(ev, function(event){
    return event.returnValue = false
  })
});

 千分位显示,常用于价格显示

function toThousands(num) {
  return parseFloat(num).toFixed(2).replace(/(\d{1,3})(?=(\d{3})+(?:\.))/g, "$1,");
}
console.log(toThousands(1000000)) // => 1,000,000.00

 字符串超出省略

 function cutstr(str,len) { 
  var restr = str; 
  var wlength = str.replace(/[^\x00-\xff]/g, "**").length; 
  if (wlength > len) { 
    for (var k = len / 2; k < str.length; k++) { 
    if (str.substr(0, k).replace(/[^\x00-\xff]/g, "**").length >= len) { 
      restr = str.substr(0, k) + "..."; 
      break; 
     } 
    } 
  } 
  return restr; 
}
console.log(cutstr('hello', 3)) // => hel...

 随机数时间戳

function uniqueId() { 
  var a = Math.random, b = parseInt; 
  return Number(new Date()).toString() + b(10 * a()) + b(10 * a()) + b(10 * a()); 
}

 获取样式属性

<style>
  .box {
    width: 200px;
    height: 200px;
  }
</style>
<div class="box" style="width: 100px"></div>
<script>
  function getStyle(elem, prop) {
    if (window.getComputedStyle) {
      return window.getComputedStyle(elem, null)[prop];
    } else {
      return elem.currentStyle[prop];
    }
  }
  console.log(getStyle(document.querySelector(".box"), "width")); // => 100px
</script>

匹配国内电话号码(0511-4405222 或 021-87888822) //////// 

function istell(str) { 
  var result = str.match(/\d{3}-\d{8}|\d{4}-\d{7}/); 
  if (result == null) return false; 
  return true; 
}
istell('0791-4405222') // => true

匹配身份证(15位或18位)

function isCardNo(card) {
    // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
    var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
    if (reg.test(card) === false) {
      return false;
    }
    return true;
  }
  console.log(isCardNo(362331...));

移动电话

function checkMobile(num) { 
  if (!(/^1[3|5|8][0-9]\d{4,8}$/.test(num))) { 
    return false; 
  } 
  return true; 
}
checkMobile(15079276737) // => true

判断输入是否是有效的电子邮件

function isemail(str) {
    var result = str.match(
      /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/
    );
    if (result == null) return false;
    return true;
  }
isemail('123@qq.com') // => true

 拆分整数与小数 

function splits(tranvalue) { 
  var value = new Array('', ''); 
  temp = tranvalue.split("."); 
  for (var i = 0; i < temp.length; i++) { 
    value = temp; 
  } 
  return value; 
}

splits('0.1') // => ["0", "1"]

 取对象最大值

var arr = [{ id: 1 }, { id: 3 }, { id: 5 }, { id: 8 }];
  console.log(Math.max(...this.arr.map((item) => item.id))); // => 8

返回数组中包含关键字的数据

var arr = ["我是你爸爸", "我是你妈妈", "我是你兄弟", "你是傻逼"];
  function indexOf(arr, str) {
    return arr.filter((item) => item.indexOf(str) != -1);
  }
  console.log(indexOf(arr, "你是")); // => ["你是傻逼"]
  console.log(arr); // => ["我是你爸爸", "我是你妈妈", "我是你兄弟", "你是傻逼"]

 

posted @ 2021-07-23 10:45  web_cnblogs  阅读(148)  评论(0)    收藏  举报