myFn(obj){ //深度遍历替换 for(let i in obj) { console.log(i + ': ' + obj[i]); if (i == 'navigator_url') { obj[i] = obj[i].replace("goods_list", "goods_list/index"); console.log(obj[i]) } if (typeof (obj[i]) == 'object') { // 判断用户是否要继续迭代 this.myFn(obj[i]); } } return obj; }
对象数据格式化
面试阿里的一道笔试题,问题是如果服务器返回了嵌套的对象,对象键名大小写不确定,如果统一让键名小写。
let obj = { a: '1', b: { c: '2', D: { E: '3' } } } 转化为如下: let obj = { a: '1', b: { c: '2', d: { e: '3' } } } // 代码实现 function keysLower(obj) { let reg = new RegExp("([A-Z]+)", "g"); for (let key in obj) { if (obj.hasOwnProperty(key)) { let temp = obj[key]; if (reg.test(key.toString())) { // 将修改后的属性名重新赋值给temp,并在对象obj内添加一个转换后的属性 temp = obj[key.replace(reg, function (result) { return result.toLowerCase() })] = obj[key]; // 将之前大写的键属性删除 delete obj[key]; } // 如果属性是对象或者数组,重新执行函数 if (typeof temp === 'object' || Object.prototype.toString.call(temp) === '[object Array]') { keysLower(temp); } } } return obj; };
数组对象数据格式根据年龄排序
var arr = [{'name': '张三', age: 26},{'name': '李四', age: 12},{'name': '王五', age: 37},{'name': '赵六', age: 4}]; arr.sort( (a,b)=> b.age-a.age); console.log(arr)
Object键值对去重
function distinct(array) { var obj = {}; return array.filter(function(item, index, array){ return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true) }) }
数组对象数据格式查找指定属性值
let json = [ {"CostTime": "310", "FromStation": "上海"}, {"CostTime": "336", "FromStation": "北京"}, {"CostTime": "310", "FromStation": "上海"}, {"CostTime": "336", "FromStation": "北京"}, {"CostTime": "310", "FromStation": "上海"}, {"CostTime": "336", "FromStation": "北京"}, {"CostTime": "310", "FromStation": "上海"}, {"CostTime": "336", "FromStation": "北京"}, {"CostTime": "310", "FromStation": "上海"}, {"CostTime": "310", "FromStation": "上海"}, {"CostTime": "336", "FromStation": "北京"} ] let filterMethod = (value) => value.CostTime == "310" //查找CostTime 中值为310的对象
let finallyData = json.filter(filterMethod); console.log(finallyData);
指定元素在数组中出现的位置
var positionIndex = []; var arr = [1,5,6,1,7,8,1,6,6,6]; var pos = arr.indexOf(1); while(pos!=-1){ positionIndex.push(pos); pos = arr.indexOf(1,pos+1); } console.log(positionIndex); // => [0,3,6]
获取url指定name的query参数
function getQueryName(name) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i=0;i<vars.length;i++) { var pair = vars[i].split("="); if(pair[0] == name){return pair[1];} } return false; }
获取url指定所有query参数
function urlToObj(str){ var obj = {}; var arr1 = str.split("?"); var arr2 = arr1[1].split("&"); for(var i=0 ; i < arr2.length; i++){ var res = arr2[i].split("="); obj[res[0]] = res[1]; } return obj; }
将obj转为url字符串
var queryString = Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
...
读取cookie
function getCookie(name){ // 读取cookie let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); arr = document.cookie.match(reg); if (arr){ return unescape(arr[2]); //unescape() 函数可对通过 escape() 编码的字符串进行解码。 }else{ return null; } }
清除数组中的[false, null, 0, NaN, undefined, ""]
let arr="123,456,4789,' ','发送到发送',,,false,".split(',')
arr.map(Number) //转换为[123, 456, 4789, NaN, NaN, 0, 0, NaN, 0]
[123, 456, 4789, NaN, NaN, 0, 0, NaN, 0].filter(val=>!(!val || val== ''));//清除数组中的[false, null, 0, NaN, undefined, ""]
//组合起来 let arr2 = arr.map(Number).filter(val=>!(!val || val== '')); //清除数组中的[false, null, 0, NaN, undefined, ""]
算法基础:展平数组
1.使用 拓展运算符 ...
let arr = [1,[2,3],[4,5]]; let arr2 = '' ; arr2=[].concat(...arr) console.log(arr2)
缺点:只能展平两层
2.递归算法
let arr=[1,[2,3],[[[4,5]]]]; flatten(arr); function flatten(arr){ return [].concat( ...arr.map(x => Array.isArray(x)?flatten(x):x) ) } console.log(flatten(arr))
3.flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
let arr3=[1,[2,3],[[[4,5]]]];
arr4=arr3.flat(Infinity) //使用 Infinity 作为深度,展开任意深度的嵌套数组
算法基础:节流算法
目的: 距离上次执行超过60毫秒,才能执行
代码:
function throttle(func,delay=60){ let lock = false; return (...args) =>{ if(lock){return} func(...args); lock = true; setTimeout( () =>{lock = false}, delay) } }
思路:执行throttle后 ,lock就是一把锁,只有当lock为false时才执行func,这把锁需要throttle距离上次执行相隔60毫秒才能为false
算法基础:防抖算法
目的: 结束操作后的一定时间内才会执行
function throttle(func,delay=300,i=null){ return (...args) => { clearInterval(i); i=setTimeout(func.bind(null,...args),delay); //i=setTimeout((...args) =>func(...args),delay);// 同上一行代码效果一样 } }
思路:不停的操作,定时器就一直重复叠加执行,定时器 i 也就每次在被重复,需要每次执行throttle时将上一次的定时器i清除,并没有执行 func .结束操作后, 在清除上一次定时器后 再次设置定时器,执行func
计算年月日
const formatDuration = ms => { if (ms < 0) ms = -ms; const time = { day: Math.floor(ms / 86400000), hour: Math.floor(ms / 3600000) % 24 - 8, //修正东八区北京时间 minute: Math.floor(ms / 60000) % 60, second: Math.floor(ms / 1000) % 60, millisecond: Math.floor(ms) % 1000 }; return Object.entries(time) .filter(val => val[1] !== 0) .map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`) .join(', '); }; // 事例 formatDuration(1001); // '1 second, 1 millisecond' formatDuration(34325055574); // '397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds' var newdate = new Date().getTime()- Date.UTC(2020,6,15,17,30) //计算 当前时间距离与某一天的毫秒差
console.log(formatDuration(newdate))
jq获取指定元素的下标
$('.nav').find('li').on('click', function () { let i = $('.nav li').index(this); console.log(i) })
树结构遍历
let tree = [{
id: '1',
title: '节点1',
children: [{
id: '1-1',
title: '节点1-1'
},
{
id: '1-2',
title: '节点1-2',
children: [{
id: '1-2-1',
title: '节点1-2-1',
}]
}
]
}, {
id: '2',
title: '节点2',
children: [{
id: '2-1',
title: '节点2-1'
},
{
id: '2-2',
title: '节点2-2'
}
]
}]
//广度优先 function treeForeach(tree, func) { let node, list = [...tree] while (node = list.shift()) { func(node) node.children && list.push(...node.children) } }
treeForeach(tree, node => {
console.log(node.title)
})
//节点1
//节点2
//节点1-1
//节点1-2
//节点2-1
//节点2-2
//节点1-2-1
//深度优先
function treeForeach2(tree, func) { //先序遍历
tree.forEach(data => {
func(data)
data.children && treeForeach2(data.children, func) //遍历子树
})
}
treeForeach2(tree, node => {
console.log(node.title)
})
//节点1
// 节点1-1
// 节点1-2
// 节点1-2-1
// 节点2
// 节点2-1
// 节点2-2
列表和树结构相互转换
let list = [{ id: '1', title: '节点1', parentId: '' }, { id: '1-1', title: '节点1-1', parentId: '1' }, { id: '1-2', title: '节点1-2', parentId: '1' }, { id: '2', title: '节点2', parentId: '' }, { id: '2-1', title: '节点2-1', parentId: '2' }, ] console.log('------------------树结构转列表结构-----递归') function treeToList(tree, result = [], level = 0) { tree.forEach(node => { result.push(node) node.level = level + 1; node.children && treeToList(node.children, result, level + 1) }) return result; }
//result 容器 ; level 记录层级 console.log(treeToList(tree)); console.log('------------------树结构转列表结构-----循环') function treeToList2(tree) { let node, result = tree.map(node => (node.level = 1, node)) for (let i = 0; i < result.length; i++) { if (!result[i].children) continue; let list = result[i].children.map(node => (node.level = result[i].level + 1, node)) result.splice(i + 1, 0, ...list) } return result } console.log(treeToList2(tree)); console.log('------------------列表结构转树结构-----') function listTotree(list) { let info = list.reduce((map, node) => (map[node.id] = node, node.children = [], map), {}) return list.filter(node => { info[node.parentId] && info[node.parentId].children.push(node) return !node.parentId }) } console.log(listTotree(list));
查找节点路径
console.log('------------------查找节点路径-----') //方法一 function treeFindPath(tree, func, path = []) { if (!tree) return [] for (const data of tree) { path.push(data.id) if (func(data)) return path if (data.children) { const findChildren = treeFindPath(data.children, func, path) if (findChildren.length) return findChildren } path.pop() } return [] } //方法二 function treeFindPath(tree, func, path = [], result = []) { for (const data of tree) { path.push(data.id) func(data) && result.push([...path]) data.children && treeFindPath(data.children, func, path, result) path.pop() } return result } let result = treeFindPath(tree, node => node.id === '1-2-1') console.log(result)
..