在开发过程中,我们经常会有操作需要进行三级联动操作,比较典型的如:省市区的选择,菜单栏的选择等。当我们遇到这个问题的时候,为了便于开发,我们都是通常使用第三方的插件来实现数据的联动效果。这时候按照联动数据,后端往往会给我们一段数据数据格式如图所示:
但当数据到了前端以后,为了方便,前端往往又需要将数据再次遍历一遍,以便将参数的属性名,或者添加额外字段,而后台为了生成这么一种数据格式,也是已经经过一次遍历的。
因此,从方案上来说,最好是一遍解决问题的。而这个遍历由前端完成更为合适一点。
这时候后端给我们的数据格式是这样的。(另外接口)
此时我们需要做的就是根据code 拼接成合适的含有父子关系的数组。根据后端定义,code 长度为 3 时,是第一级,为 6 时为第二级,以此类推。001 的子元素为 001001, 001 的兄弟元素为 002。
遍历的代码比较简单,只是在我没有想到在这个地方,根据 对象变量存储的数据是真实对象所在地址字节时 这个概念来进行遍历的时候。对于如何编写这一函数,我无法进行。
const arr = [ { "code": "001" }, { "code": "001001" }, { "code": "002" }, { "code": "002001" }, { "code": "002002" }, { "code": "002003" }, { "code": "002004" }, { "code": "002005" } ] //因为是值的引用,所以根据这一存储的原理,每次遍历以后都可以将之前的数据补充完整,所以遍历以便以后, // obj[001]就是code 为001 且包括其所有子元素的一个对象, // obj[001001]就是code 为001001 且包括其所有子元素的一个对象(不包括父元素) // 而我们obj[001]也早已经将数据保存到了resultArr中。这时候resultArr就是最终结果。 // (数组也是存储的每个元素的真实所在位置的地址的一个数组) let obj = new Map() //以 key :value 的形式,根据code存放每个value let resultArr = [] arr.map((currentValue, index, array) => { let code = currentValue.code obj[code] = currentValue // 当code长度为3时,代表为一级目录 if (currentValue.code.length === 3) { resultArr.push(obj[code]) } else { let auth = currentValue.auth let parentid = currentValue.code.substring(0, currentValue.code.length - 3) // 获取当前currentValue的父元素的pid if (obj[parentid].list) { obj[parentid].list.push(currentValue) } else { obj[parentid].list = [] obj[parentid].list.push(currentValue) } } }) console.log(resultArr)
说回原理,代码的原理在于 对于对象类数据,值的存储不是存放在栈中,而是存储在堆中,let obj = {} 实际上obj 的真实信息是这个存在与堆中的,而obj实际存储的是这个对象的地址,而使用obj时我们是根据在obj所获取的地址,找到对应的堆数据进行修改。同样的,在上述代码中,我们虽然没有直接修改 resultArr ,但我们通过修改 obj[code] 的值,对于引用obj[code] 的resultArr而言,其内值已经发生变化。简单代码如下
let obj1 = { name:'张三', } let obj2 = obj1 obj2.name = '李四' console.log(obj1.name) // 李四
详细内容可以百度或者谷歌搜索 js对象的赋值的引用
参考资料:JavaScript高级程序设计 第四章 4.1.2 复制变量值