常用的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); // => ["我是你爸爸", "我是你妈妈", "我是你兄弟", "你是傻逼"]
浙公网安备 33010602011771号