js 遞歸json樹實現(xiàn)根據(jù)子id查父id的方法分析
本文實例講述了js 遞歸json樹實現(xiàn)根據(jù)子id查父id的方法。分享給大家供大家參考,具體如下:
最近做了一個類似用js實現(xiàn)思維導圖的功能,作為思維導圖,一定會有樹狀結構的數(shù)據(jù)產(chǎn)生,在操作里面的節(jié)點時會經(jīng)常需要查找節(jié)點 的父節(jié)點及父節(jié)點。
對于未知層級的樹狀數(shù)據(jù),用for循環(huán)是無法實現(xiàn)的,因為不知道要循環(huán)幾層,那么最合適的方法就是用js遞歸
界面結構:

json數(shù)據(jù):
"orgTreeData":{
"nodeId":"19A5B",
"nodeName":"預分析用戶:1313.85萬人",
"nodeType":"root",
"expand":true,
"dataCnt":13138494,
"children":[
{
"nodeId":"19A5B_19A5C",
"nodeName":"客戶狀態(tài)",
"nodeType":"tag",
"children":[
{
"nodeId":"19A5B_19A5C_19A5E",
"nodeName":"包含(實名制停機,IPBUS帳戶封鎖停機)",
"dataCnt":"0人",
"nodeType":"domain",
"counted":2,
"children":[
{
"nodeId":"19A5B_19A5C_19A5E_19A67",
"nodeName":"積分",
"nodeType":"tag",
"children":[
],
"expand":true,
"counted":0,
"condType":"1",
"dataType":1,
"propType":"1",
"propSql":"",
"labelId":"BLD00013",
"linked":false,
"linkedId":""
},
{
"nodeId":"19A5B_19A5C_19A5E_19A68",
"nodeName":"是否通信客戶",
"nodeType":"tag",
"children":[
],
"expand":true,
"counted":0,
"condType":"3",
"dataType":1,
"propType":"4",
"propSql":"",
"labelId":"BLD00010",
"linked":false,
"linkedId":""
}
],
"expand":true,
"expressType":"7",
"expressValue1":[
"17",
"14"
],
"expressValue2":"",
"expressValue3":"17##14",
"expressValue4":"實名制停機##IPBUS帳戶封鎖停機",
"expressValue5":"實名制停機,IPBUS帳戶封鎖停機",
"linked":false,
"linkedId":""
},
{
"nodeId":"19A5B_19A5C_19A60",
"nodeName":"包含(營業(yè)銷戶)",
"dataCnt":"0人",
"nodeType":"domain",
"counted":2,
"children":[
{
"nodeId":"19A5B_19A5C_19A60_19A69",
"nodeName":"入網(wǎng)歸屬地域",
"nodeType":"tag",
"children":[
{
"nodeId":"19A5B_19A5C_19A60_19A69_19A6A",
"nodeName":"包含(鄂爾多斯,阿盟)",
"dataCnt":"",
"nodeType":"domain",
"counted":0,
"children":[
],
"expand":true,
"expressType":"7",
"expressValue1":[
"477",
"482"
],
"expressValue2":"",
"expressValue3":"477##482",
"expressValue4":"鄂爾多斯##阿盟",
"expressValue5":"鄂爾多斯,阿盟",
"linked":false,
"linkedId":""
}
],
"expand":true,
"counted":0,
"condType":"2",
"dataType":1,
"propType":"3",
"propSql":"1005",
"labelId":"BLD00017",
"linked":false,
"linkedId":""
}
],
"expand":true,
"expressType":"7",
"expressValue1":[
"40"
],
"expressValue2":"",
"expressValue3":"40",
"expressValue4":"營業(yè)銷戶",
"expressValue5":"營業(yè)銷戶",
"linked":false,
"linkedId":""
}
],
"expand":true,
"counted":0,
"condType":"2",
"dataType":1,
"propType":"3",
"propSql":"1002",
"labelId":"BLD00004",
"linked":false,
"linkedId":""
},
{
"nodeId":"19A5B_19A61",
"nodeName":"全球通級別 && 全球通級別",
"nodeType":"tag",
"children":[
],
"expand":true,
"counted":0,
"condType":"2",
"dataType":1,
"propType":"3",
"propSql":"1004",
"labelId":"BLD00008",
"linked":true,
"linkedId":"19A5B_19A64"
},
{
"nodeId":"19A5B_19A62",
"nodeName":"同證件號碼數(shù)量",
"nodeType":"tag",
"children":[
],
"expand":true,
"counted":0,
"condType":"1",
"dataType":1,
"propType":"1",
"propSql":"",
"labelId":"BLD00009",
"linked":false,
"linkedId":""
}
]
}
我這個對象結構是按nodeId匹配的,每個下級為children數(shù)組。
如果我想點擊任何一個節(jié)點根據(jù)節(jié)點nodeId得到它的父節(jié)點nodeId,就得把整個json樹遞歸遍歷一遍,知道找到這個節(jié)點,從而得到它的父節(jié)點
關于遞歸,一定要掌握好結束條件,懂得何時return,不然會出現(xiàn)返回不出值或者循環(huán)提前結束的情況。
js代碼:
//傳入?yún)?shù):需要遍歷的json,需要匹配的id
findPnodeId(data,nodeId){
//設置結果
let result;
if (!data) {
return;//如果data傳空,直接返回
}
for (var i = 0; i < data.children.length; i++) {
let item = data.children[i];
if (item.nodeId == nodeId) {
result=data.nodeId;
//找到id相等的則返回父id
return result;
} else if (item.children && item.children.length > 0) {
//如果有子集,則把子集作為參數(shù)重新執(zhí)行本方法
result= findPnodeId(item, nodeId);
//關鍵,千萬不要直接return本方法,不然即使沒有返回值也會將返回return,導致最外層循環(huán)中斷,直接返回undefined,要有返回值才return才對
if(result){
return result;
}
}
}
//如果執(zhí)行循環(huán)中都沒有return,則在此return
return result;
}

總之,遞歸相當于上圖中的軌跡查找。
條件執(zhí)行到 需要 重新執(zhí)行 findPnodeId 方法的地方開始一頭扎進去,如果第下一次執(zhí)行找到了符合條件的值,則return出來,返回上一層,下一層的 findPnodeId 方法結束,返回值,上一層的findPnodeId方法也就直接return結束了。

如果下一層方法 進入循環(huán)第一次依然沒有找到 符合的值 ,如果還有子集,則會繼續(xù)向更下一層進發(fā);就像上圖中的紅線,直到?jīng)]有子集才結束,所以千萬不讓直接 在遞歸 findPnodeId 方法前直接return,也就是這樣:
else if (item.children && item.children.length > 0) {
return findPnodeId(item, nodeId);
}
這樣會使 json在第一條樹軌跡結束時(上圖中的紅色軌跡)如果找不到值 強制 retrun undefined,因為沒一個方法都向上return,for循環(huán)中,一旦return,會直接打斷循環(huán),使方法結束,結果是最底層 的undefined 直接return到頂層,頂層直接將undefined return出來,根本沒有走第234條線,所以一定要先判斷一下是否返回值再return,像這樣:
} else if (item.children && item.children.length > 0) {
result= this.findPnodeId(item, nodeId);
if(result){
return result;
}
}
那么如果方法前不寫return會怎樣?
是方法無法return,依然無法遞歸
PS:關于json操作,這里再為大家推薦幾款比較實用的json在線工具供大家參考使用:
在線JSON代碼檢驗、檢驗、美化、格式化工具:
http://tools.jb51.net/code/json
JSON在線格式化工具:
http://tools.jb51.net/code/jsonformat
在線XML/JSON互相轉換工具:
http://tools.jb51.net/code/xmljson
json代碼在線格式化/美化/壓縮/編輯/轉換工具:
http://tools.jb51.net/code/jsoncodeformat
在線json壓縮/轉義工具:
http://tools.jb51.net/code/json_yasuo_trans
更多關于JavaScript相關內(nèi)容可查看本站專題:《JavaScript中json操作技巧總結》、《JavaScript查找算法技巧總結》、《JavaScript錯誤與調(diào)試技巧總結》、《JavaScript數(shù)據(jù)結構與算法技巧總結》、《JavaScript遍歷算法與技巧總結》及《JavaScript數(shù)學運算用法總結》
希望本文所述對大家JavaScript程序設計有所幫助。
相關文章
JavaScript中async與await實現(xiàn)原理與細節(jié)
這篇文章主要介紹了JavaScript中async與await實現(xiàn)原理與細節(jié),文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09
JavaScript函數(shù)封裝隨機顏色驗證碼(完整代碼)
這篇文章主要介紹了JavaScript函數(shù)封裝隨機顏色驗證碼(完整代碼),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12
JavaScript屏蔽指定區(qū)域內(nèi)右鍵菜單
有時候需要屏蔽部分區(qū)域內(nèi)的右鍵菜單,下面的代碼大家可以測試下。2010-03-03
JavaScript刪除數(shù)組中指定元素5種方法例子
這篇文章主要給大家介紹了關于JavaScript刪除數(shù)組中指定元素5種方法,在最近的項目中,有用到js對數(shù)組的操作,所以這里總結一下,需要的朋友可以參考下2023-07-07

