JavaScript樹形結(jié)構(gòu)數(shù)組處理之遞歸問題
JS樹形結(jié)構(gòu)數(shù)組處理之遞歸
經(jīng)典示例
var data = [ ?{ ? ? ?name: "所有物品", ? ? ?children: [ ? ? ? ? ?{ ? ? ? ? ? ? ?name: "水果", ? ? ? ? ? ? ?children: [{name: "蘋果", children: [{name: '青蘋果'}, {name: '紅蘋果'}]}] ? ? ? ? ?}, ? ? ? ? ?{ ? ? ? ? ? ? ?name: '主食', ? ? ? ? ? ? ?children: [ ? ? ? ? ? ? ? ? ?{name: "米飯", children: [{name: '北方米飯'}, {name: '南方米飯'}]} ? ? ? ? ? ? ?] ? ? ? ? ?}, ? ? ? ? ?{ ? ? ? ? ? ? ?name: '生活用品', ? ? ? ? ? ? ?children: [ ? ? ? ? ? ? ? ? ?{name: "電腦類", children: [{name: '聯(lián)想電腦'}, {name: '蘋果電腦'}]}, ? ? ? ? ? ? ? ? ?{name: "工具類", children: [{name: "鋤頭"}, {name: "錘子"}]}, ? ? ? ? ? ? ? ? ?{name: "生活用品", children: [{name: "洗發(fā)水"}, {name: "沐浴露"}]} ? ? ? ? ? ? ?] ? ? ? ? ?} ? ] }] //遞歸遍歷實(shí)現(xiàn) var recursiveFunction = function(){ ? ? var str = '' ? ? const getStr = function(list){ ? ? ? ? list.forEach(function(row){ ? ? ? ? ? ? if(row.children){ ? ? ? ? ? ? ? ? getStr(row.children) ? ? ? ? ? ? }else { ? ? ? ? ? ? ? ? str += row.name + ";" ? ? ? ? ? ? } ? ? ? ? }) ? ? } ? ? getStr(data) ? ? console.log(str) } recursiveFunction() //輸出:青蘋果;紅蘋果;北方米飯;南方米飯;聯(lián)想電腦;蘋果電腦;鋤頭;錘子;洗發(fā)水;沐浴露;
簡單理解:
let arr = [ ?? ?{ name: '小明同學(xué)', children: [ { name: '小明同學(xué)', children: [ { name: '小明同學(xué)' } ] } ] } ] function fn (arr, newArr = []) { ?? ?arr.forEach(item => { ?? ??? ?typeof item === 'object' && item.name && newArr.push(item.name) ?// 先判斷當(dāng)前項(xiàng)是否是對(duì)象。 當(dāng)前項(xiàng)是否存在你想要的數(shù)據(jù)。都符合,把數(shù)據(jù)push到新數(shù)組里 ?? ??? ?item.children && item.children instanceof Array && fn(item.children, newArr) // 當(dāng)前項(xiàng)是否還有子節(jié)點(diǎn),子節(jié)是否是數(shù)組, 如果是繼續(xù)調(diào)用自己。再循環(huán)遍歷一次. ?? ?}) ?? ?return newArr } fn(arr) // ['小明同學(xué)','小明同學(xué)','小明同學(xué)'] function fn1 (arr, newArr = []) { ?? ?function recursion (arr) { ?? ??? ?arr.forEach(item => {? ?? ??? ??? ?newArr.push(item.name) ?? ??? ??? ?item.children && recursion(item.children) ?? ??? ?}) ?? ?} ?? ?recursion(arr) ?? ?return newArr } fn1(arr) // ['小明同學(xué)','小明同學(xué)','小明同學(xué)']
遞歸解決多級(jí)數(shù)組
1.我們考慮利用遞歸 就必須等有一個(gè)判斷條件 中斷 遞歸 不然容易出現(xiàn)死循環(huán)
2.我們?cè)谶M(jìn)如函數(shù)遞歸是 要注意第二次調(diào)用自身是 函數(shù)的參數(shù)要是數(shù)據(jù)的子數(shù)據(jù)
實(shí)現(xiàn)邏輯
//js遍歷對(duì)象 function TraversalObject(obj) { ? ? for (var a in obj) { ? ? ? ? if (typeof (obj[a]) == "object") { ? ? ? ? ? ? TraversalObject(obj[a]); //遞歸遍歷 ? ? ? ? } ? ? ? ? else { ? ? ? ? ? ? alert(a + "=" + obj[a]);//值就顯示 ? ? ? ? } ? ? } } //遍歷對(duì)象中所有Ur的值 function TraversalObject(obj) { ? ? for (var a in obj) { ? ? ? ? if(a=="Url") ? ?alert(obj[a]);/ /顯示URL的值 ? ? ? ? if (typeof (obj[a]) == "object") { ? ? ? ? ? ? TraversalObject(obj[a]); //遞歸遍歷 ? ? ? ? } ? ? } }
這種遍歷方法在對(duì)象不規(guī)則但需要獲取相同屬性時(shí)起到非常好的作用。
復(fù)雜遞歸
遞歸屬性遍歷
一般來說,在JavaScript中考慮復(fù)合類型的深層復(fù)制的時(shí)候,往往就是指對(duì)于Date、Object與Array這三個(gè)復(fù)合類型的處理。
我們能想到的最常用的方法就是先創(chuàng)建一個(gè)空的新對(duì)象,然后遞歸遍歷舊對(duì)象,直到發(fā)現(xiàn)基礎(chǔ)類型的子節(jié)點(diǎn)才賦予到新對(duì)象對(duì)應(yīng)的位置。
不過這種方法會(huì)存在一個(gè)問題,就是JavaScript中存在著神奇的原型機(jī)制,并且這個(gè)原型會(huì)在遍歷的時(shí)候出現(xiàn),然后原型不應(yīng)該被賦予給新對(duì)象。
那么在遍歷的過程中,我們應(yīng)該考慮使用hasOenProperty方法來過濾掉那些繼承自原型鏈上的屬性:
function clone(obj) { var copy; ? ? // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; ? ? // Handle Date if (obj instanceof Date) { ? ? ? ? copy = new Date(); ? ? ? ? copy.setTime(obj.getTime()); return copy; ? ? } ? ? // Handle Array if (obj instanceof Array) { ? ? ? ? copy = []; for (var i = 0, len = obj.length; i < len; i++) { ? ? ? ? ? ? copy[i] = clone(obj[i]); ? ? ? ? } return copy; ? ? } ? ? // Handle Object if (obj instanceof Object) { ? ? ? ? copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); ? ? ? ? } return copy; ? ? } throw new Error("Unable to copy obj! Its type isn't supported."); }
調(diào)用如下:
// This would be cloneable: var tree = { ? ? "left" ?: { "left" : null, "right" : null, "data" : 3 }, ? ? "right" : null, ? ? "data" ?: 8 }; // This would kind-of work, but you would get 2 copies of the? // inner node instead of 2 references to the same copy var directedAcylicGraph = { ? ? "left" ?: { "left" : null, "right" : null, "data" : 3 }, ? ? "data" ?: 8 }; directedAcyclicGraph["right"] = directedAcyclicGraph["left"]; // Cloning this would cause a stack overflow due to infinite recursion: var cylicGraph = { ? ? "left" ?: { "left" : null, "right" : null, "data" : 3 }, ? ? "data" ?: 8 }; cylicGraph["right"] = cylicGraph;
不限層級(jí)
//后臺(tái)返回來的數(shù)據(jù)形式 ?const data = { ? ? "code":"0", ? ? "data":[ ? ? ? ? { ? ? ? ? ? ? "data":{ ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司", ? ? ? ? ? ? ? ? isLeaf:false, ? ? ? ? ? ? ? ? "id":1, ? ? ? ? ? ? ? ? "child":{ ? ?? ? ? ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司第一分部", ? ? ? ? ? ? ? ? ? ? ?isLeaf:false, ? ? ? ? ? ? ? ? ? ? "id":2, ? ? ? ? ? ? ? ? ? ? "child":{ ? ? ? ? ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司第二分部", ? ? ? ? ? ? ? ? ? ? ? ? ?isLeaf:false, ? ? ? ? ? ? ? ? ? ? ? ? "id":3, ? ? ? ? ? ? ? ? ? ? ? ? "child":{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司第三分部", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?isLeaf:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? "id":4, ? ? ? ? ? ? ? ? ? ? ? ? ? ? "child":{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司第第四分部", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?isLeaf:true, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "id":5, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "child":{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//此處省略層數(shù)不定 可能根據(jù)不同的人的權(quán)限層級(jí)樹不一樣 isLeaf為true 代表著在往后已經(jīng)沒有子層級(jí) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ], ? ? "message":"成功" } ? //因?yàn)殚_發(fā)中我個(gè)人自己開發(fā)和使用的控件是數(shù)組形式的 ?后端不小心弄成都是對(duì)象形式返回來 因?yàn)樯婕暗臉I(yè)務(wù)關(guān)聯(lián)表比較多 不方便改 所以作為前端還得處理,個(gè)人處理如下: ? 預(yù)期想達(dá)到的數(shù)據(jù)結(jié)構(gòu)效果: ?? ?"data":[ ? ? { ? ? ? ? "name":"xx集團(tuán)香港分公司", ? ? ? ? isLeaf:false, ? ? ? ? "id":2, ? ? ? ? "child":[ ?? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司", ? ? ? ? ? ? ? ? isLeaf:false, ? ? ? ? ? ? ? ? "id":3, ? ? ? ? ? ? ? ? "child":[ ?? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司", ? ? ? ? ? ? ? ? ? ? ? ? isLeaf:false, ? ? ? ? ? ? ? ? ? ? ? ? "id":4, ? ? ? ? ? ? ? ? ? ? ? ? "child":[ ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "name":"xx集團(tuán)香港分公司", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? isLeaf:true, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "id":5, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? child:[{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }] ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? } ? ? ? ? ] ? ? } ] ? ?//復(fù)雜的對(duì)象轉(zhuǎn)化成為數(shù)組 遞歸實(shí)現(xiàn) ? ? objectToarray(dataObj, arr) { ? ? ? let newObj = {}; ? ? ? if (Object.prototype.toString.call(dataObj) === "[object Object]") { ? ? ? ? for (let i in dataObj) { ? ? ? ? ? newObj[i] = ? ? ? ? ? ? i === "child" && !dataObj.isLeaf ? ? ? ? ? ? ? ? this.objectToarray(dataObj[i], []) ? ? ? ? ? ? ? : dataObj[i]; ? ? ? ? } ? ? ? ? arr.push(newObj); ? ? ? } ? ? ? return arr; ? ? } //取到數(shù)據(jù)和將數(shù)據(jù)塞進(jìn)去進(jìn)行處理 靜靜等待結(jié)果 ?const dataObj = data.data[0].data; ?const result = objectToarray(dataObj , [])?
JS必會(huì)技巧之遞歸樹結(jié)構(gòu)
列表轉(zhuǎn)化為樹結(jié)構(gòu)(遞歸樹形結(jié)構(gòu))
實(shí)際開發(fā)中,經(jīng)常會(huì)遇到的業(yè)務(wù)需求中,后端傳過來的是數(shù)組中包含許多“形式一樣”的對(duì)象,但實(shí)際這些對(duì)象是由層級(jí)關(guān)系的(樹結(jié)構(gòu))。
因此前端需要經(jīng)過處理,轉(zhuǎn)化為樹結(jié)構(gòu)。
const list = [ { id:1, pid:0, name:'中國' }, { id:2, pid:1, name:'北京' }, { id:3, pid:1, name:'深圳' }, { id:4, pid:1, name:'武漢' }, { id:5, pid:1, name:'西安' }, { id:6, pid:2, name:'朝陽' }, { id:7, pid:2, name:'海淀' } ] const trancListToTreeData = (data,rootVal)=>{ const res = []; //遍歷查找 data.forEach((item)=>{ if(item.pid == rootVal){ //找到了根--找根下面的數(shù)據(jù) res.push(item); const children = trancListToTreeData(data,item.id) //子節(jié)點(diǎn) children.length &&(item.children = children) } }) return res; } //遍歷樹形的原則--有頭,才知道從哪開始 //要找根 console.log(trancListToTreeData (list,0))
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- JS前端二維數(shù)組生成樹形結(jié)構(gòu)示例詳解
- JavaScript數(shù)組扁平轉(zhuǎn)樹形結(jié)構(gòu)數(shù)據(jù)(Tree)的實(shí)現(xiàn)
- JS實(shí)現(xiàn)樹形結(jié)構(gòu)與數(shù)組結(jié)構(gòu)相互轉(zhuǎn)換并在樹形結(jié)構(gòu)中查找對(duì)象
- JavaScript平鋪數(shù)組轉(zhuǎn)樹形結(jié)構(gòu)的實(shí)現(xiàn)示例
- 如何將JavaScript將數(shù)組轉(zhuǎn)為樹形結(jié)構(gòu)
- JavaScript 實(shí)現(xiàn)普通數(shù)組數(shù)據(jù)轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)的步驟說明
相關(guān)文章
Javascript實(shí)現(xiàn)獲取及設(shè)置光標(biāo)位置的方法
這篇文章主要介紹了Javascript實(shí)現(xiàn)獲取及設(shè)置光標(biāo)位置的方法,涉及javascript針對(duì)頁面光標(biāo)位置的相關(guān)操作技巧,具有良好的兼容性,非常簡單實(shí)用,需要的朋友可以參考下2015-07-07解決webpack無法通過IP地址訪問localhost的問題
下面小編就為大家分享一篇解決webpack無法通過IP地址訪問localhost的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-02-02JS實(shí)現(xiàn)文字向下滾動(dòng)完整實(shí)例
這篇文章主要介紹了JS實(shí)現(xiàn)文字向下滾動(dòng)的方法,以一個(gè)完整實(shí)例形式詳細(xì)分析了html頁面布局、css樣式及對(duì)應(yīng)的js滾動(dòng)功能實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-02-02JavaScript中英文字符長度統(tǒng)計(jì)方法示例【按照中文占2個(gè)字符】
這篇文章主要介紹了JavaScript中英文字符長度統(tǒng)計(jì)方法,涉及javascript針對(duì)中英文字符的匹配與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-01-01利用Javascript實(shí)現(xiàn)簡單的轉(zhuǎn)盤抽獎(jiǎng)
這篇文章主要介紹了利用Javascript實(shí)現(xiàn)的簡單的轉(zhuǎn)盤抽獎(jiǎng),文中分享了兩種抽獎(jiǎng)效果,一種是默認(rèn)轉(zhuǎn)動(dòng),一種是需要點(diǎn)擊開始轉(zhuǎn)動(dòng)的,并給出了晚上的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02JavaScript中的16進(jìn)制字符(改進(jìn))
后來經(jīng)過自己的測(cè)試,發(fā)現(xiàn)將字符轉(zhuǎn)換為十六進(jìn)制的方法不完善。2011-11-11通過JS獲取Request.QueryString()參數(shù)的值實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄ㄟ^JS獲取Request.QueryString()參數(shù)的值實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09