面试复盘:数组扁平化,优化资源加载的localstorge,对象扁平化

数组与对象处理技巧:扁平化、资源优化与本地存储
本文回顾了一次面试中关于数组扁平化、资源优化利用localStorge和sessionStorge,以及对象扁平化的讨论。提到数组扁平化最简单方法是toString,但效率上set比indexOf更快。链表查找速度较慢,数组查找更快。优化资源时,sessionStorge适合短暂存储,而localStorge更新可通过chunkhash或版本号。对象扁平化通常利用id的唯一性,递归或利用visited数组优化。还讨论了setTimeout的默认延迟为0,以及闭包中传递window对象的益处。

昨天笔试遇到一个数组扁平化的问题,后来被提醒有一个很简便的方法,toString方法。
平时用到的地方可能只是在向后台传数组的时候,用的不是json格式需要特殊化处理,比如一些批量删除的功能,在以前工作的公司就是接受一个字符串,id通过逗号分隔,再传数组的时候用了toString。当然也有另一种传数组的方法,使用qs库调用里面提供的qs.stringify()
那回到数组扁平化的题
const a = [1,2,2,3,[4,6],[7,7,8,[9,10]],[5]]
将这个数组扁平化去重升序:
最简便的方法:

[...new Set(a.toString().split(',').map(item => +item))].sort((a,b) => a-b)

我当时的想法是遍历整个数组,如果当前元素是数组就递归,再把元素放进去,再判断是否有跟数组中重复,再要插入排序,这里也贴一下代码

var newArr = []
function parseArr(arr) {
	arr.forEach(el => {
		if(Array.isArray(el)) {
			parseArr(el)
		}else{
			newArr.indexOf(el) === -1 && newArr.push(el)
			for(let i=newArr.length - 2; i>=0 && newArr[i] > newArr[i+1];i--) {
				let temp = newArr[i]
				newArr[i] = newArr[i+1]
				newArr[i+1] = temp
			}
		}
	})
}

当数组较大的时候indexof去重那部分没有set快

还有被问到数组跟链表查找哪个比较快
一开始我以为那种应该会没有差别,但其实链表是通过指针去寻找下一个节点,并不是连续存储的,在移到下一个元素的时候数组会快一点

谈到优化资源,我讲到了可以在localStorge存储数据,但实际上用到更多的是sessionStorge,因为sessionStorge会在关闭页面就清除掉,在刷新页面的时候会被保留,而localStorge什么时候更新的问题,一开始想到的可以用时间戳,后来想到的是像webpack那样的chuckhash这种,如果文件改变了hash会改变,了解了一下这个hash怎么生成的,调用的是node.js的采用hash = crypto.createHash()方法指定一种创建hash的方法,常见有’sha256’, ‘sha512’,然后再调用hash.update(data),当然也有更简单的存一个版本号(对变动不频繁的这样也可)

对象扁平化这里是最常见的树形数组转成对象的那种,在之前公司采用的是通过利用id的唯一性构建一个对象来实现的,面试的时候要求是用递归,时间比较急没有写完,再谈题的时候提到可以提前退出递归,剪枝的地方可以考虑开一个visited数组如果visited过了就不再递归提前退出

var data = [
    { id: 1, parentId: 0, name: "一级菜单A", rank: 1 },
    { id: 2, parentId: 0, name: "一级菜单B", rank: 1 },
    { id: 3, parentId: 0, name: "一级菜单C", rank: 1 },
    { id: 4, parentId: 1, name: "二级菜单A-A", rank: 2 },
    { id: 5, parentId: 1, name: "二级菜单A-B", rank: 2 },
    { id: 6, parentId: 2, name: "二级菜单B-A", rank: 2 },
    { id: 7, parentId: 4, name: "三级菜单A-A-A", rank: 3 },
    { id: 8, parentId: 7, name: "四级菜单A-A-A-A", rank: 4 },
    { id: 9, parentId: 0, name: "五级菜单A-A-A-A-A", rank: 5 },
    { id: 10, parentId: 9, name: "六级菜单A-A-A-A-A-A", rank: 6 },
    { id: 11, parentId: 10, name: "七级菜单A-A-A-A-A-A-A", rank: 7 },
    { id: 12, parentId: 11, name: "八级菜单A-A-A-A-A-A-A-A", rank: 8 },
    { id: 13, parentId: 12, name: "九级菜单A-A-A-A-A-A-A-A-A", rank: 9 },
    { id: 14, parentId: 13, name: "十级菜单A-A-A-A-A-A-A-A-A-A", rank: 10 },
]
function parseTree(data) {
    let newArr = []
    let visited= new Array(data.length).fill(false)
    function parseData(parent) {
        for (let j = 0; j < data.length; j++) {
            if(visited[j])continue
            if (data[j].parentId === parent.id) {
                visited[j] = true
                newArr.push(data[j]);
                (parent.children = parent.children || []).push(data[j])
                parseData(data[j])
            } 
        }
    }
    newArr.push({
        id: 0,
        children: []
    })
    parseData(newArr[0])
    console.log(newArr)
}
parseTree(data)

个人比较喜欢object的方法,下面是我封装的一个方法,支持不同id和parentId的名字

export function parseTree(data, pid, idName, parentIdName) {
  var newData = {}
  data.forEach(function(item) {
    var id = item[idName]
    var _this = newData[id] = newData[id] ? Object.assign(item, newData[id]) : item
    var pid = _this[parentIdName]
    var parent = newData[pid] = newData[pid] || {};
    (parent.children = parent.children || []).push(_this)
  })
  return newData[pid]
}

不需要递归,但是要有一个复制对象的动作

还有一点setTimeout(fn,delay),delay是可以省略的默认是0,就是较快执行,这个是我手写代码的时候忘记写延迟多少秒,被问如果这样写会不会报错,其实是不会报错的,而且还会在当主线程空闲的前提下执行

还有一点是闭包中传window对象的好处,除了想到变成局部变量,提高作用链寻找变量的这个点,就没有想到有什么其他好处了,希望知道的朋友可以告知一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值