成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

代碼解析 | '樹(shù)'的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化

Scholer / 3399人閱讀

摘要:也正是引用類(lèi)型的數(shù)據(jù)的這個(gè)特點(diǎn),保證了我們的無(wú)論多少層的子元素都能被正確的穿到了對(duì)應(yīng)的父元素上五總結(jié)丈高樓始于平地,打好基礎(chǔ)知識(shí)異常重要文章出自成都社區(qū),歡迎大家的加入,和我們一起討論學(xué)習(xí)

一、問(wèn)題描述

相信做前端的小伙伴都有遇到過(guò)將一個(gè)平鋪的 ‘樹(shù)’ 結(jié)構(gòu)轉(zhuǎn)換成一個(gè)真正的 ‘樹(shù)’ 結(jié)構(gòu),比如說(shuō)下面這種:

var _JSON_ = [
        {id: 7,  name: "豬",  pid: 2},
        {id: 8,  name: "牛",  pid: 2},
        {id: 9,  name: "羊",  pid: 2},
        {id: 13,  name: "三黃雞",  pid: 4},
        {id: 14,  name: "白羽雞",  pid: 4},
        {id: 15,  name: "火雞",  pid: 4},
        {id: 4,  name: "雞",  pid: 1},
        {id: 5,  name: "鴨",  pid: 1},
        {id: 6,  name: "鵝",  pid: 1},
        {id: 10,  name: "粟",  pid: 3},
        {id: 11, name: "稻",  pid: 3},
        {id: 12, name: "黍",  pid: 3},
        {id: 1,  name: "禽"},
        {id: 2,  name: "獸"},
        {id: 3,  name: "谷"}    
    ];

最終要轉(zhuǎn)換成類(lèi)似如下的格式,方便在頁(yè)面渲染:

 [
      {id: 1,  name: "禽", pid: 0, children: [
          {id: 4,  name: "雞",  pid: 1, children: [
              {id: 13,  name: "三黃雞",  pid: 4},
              {id: 14,  name: "白羽雞",  pid: 4},
              {id: 15,  name: "火雞",   pid: 4}
          ]},
          {id: 5,  name: "鴨",  pid: 1, children: []},
          {id: 6,  name: "鵝",  pid: 1, children: []}
      ]},
      {id: 2,  name: "獸", pid: 0, children: [
          {id: 7,  name: "豬",  pid: 2, children: []},
          {id: 8,  name: "牛",  pid: 2, children: []},
          {id: 9,  name: "羊",  pid: 2, children: []}
      ]},
      {id: 3,  name: "谷", pid: 0, children: [
          {id: 10, name: "粟",  pid: 3, children: []},
          {id: 11, name: "稻",  pid: 3, children: []},
          {id: 12, name: "黍",  pid: 3, children: []}
      ]}    
    ]

你的方法是什么樣的呢?思考中...

二、代碼鑒賞

相信有的小伙伴會(huì)是和網(wǎng)上大多數(shù)能搜到的答案一樣,用好幾個(gè)循環(huán)來(lái)實(shí)現(xiàn),在這里給大家解讀一下,我認(rèn)為看到代碼最少的一種解決方案,該方案出自FCC成都社區(qū)的水歌之手,Jsbin代碼地址:https://jsbin.com/budapagito/...

 //十一行的代碼實(shí)現(xiàn)將 ’平鋪的樹(shù)’ 轉(zhuǎn)換為 ‘立體的樹(shù)’ 結(jié)構(gòu)
 function Array2Tree() {
    
        var TempMap = { };
      
        $.each($.extend(true, [ ], arguments[0]),  function () {
        
            var _This_ = TempMap[ this.id ];
          
            _This_ = TempMap[ this.id ] = _This_ ?
                $.extend(this, _This_)  :  this;
              
            this.pid = this.pid || 0;
          
            var _Parent_ = TempMap[ this.pid ] = TempMap[ this.pid ]  ||  { };
          
            (_Parent_.children = _Parent_.children || [ ]).push(_This_);
        });
      
        return TempMap[0].children;
    }

    console.log(JSON.stringify(
      Array2Tree(_JSON_), null, 4
    ));
三、知識(shí)點(diǎn)分析

在看一段代碼時(shí),我們首先要了解里面涉及到的知識(shí)點(diǎn)(從方法入口開(kāi)始):

1、JSON.stringify(Array2Tree(_JSON_), null, 4)

將Array2Tree(_JSON_)這個(gè)函數(shù)返回的數(shù)據(jù)處理成Json,"4"代表縮進(jìn)4空白字符串,用于美化輸出(pretty-print)

2、arguments[0]

arguments對(duì)象是所有函數(shù)中可用的局部變量。你可以使用arguments對(duì)象在函數(shù)中引用函數(shù)的參數(shù)。此對(duì)象包含傳遞給函數(shù)的每個(gè)參數(shù)的條目,第一個(gè)條目的索引從0開(kāi)始。這里的arguments[0]實(shí)際就是取得我們傳入函數(shù)的_JSON_數(shù)組。

3、$.extend()

描述:將兩個(gè)或更多對(duì)象的內(nèi)容合并到第一個(gè)對(duì)象。

也可以是$.extend(boolean,dest,src1,src2,src3...)

第一個(gè)參數(shù)boolean代表是否進(jìn)行深度拷貝不含第一個(gè)參數(shù)boolean,它的含義是將src1,src2,src3...合并到dest中,返回值為合并后的dest,由此可以看出該方法合并后,是修改了dest的結(jié)構(gòu)的。所以這里$.extend(true, [ ], arguments[0])的意思就是把傳的_JSON_數(shù)組合并到一個(gè)空的數(shù)組 [ ] 上去, 保證后續(xù)的操作不會(huì)改變arguments[0]的結(jié)構(gòu)。

備注:$.extend(true, [ ], arguments[0]) , 也是可以直接遍歷arguments[0]:

4、$.each()

jQuery的each方法是跟each的語(yǔ)義一樣是遍歷的作用。
當(dāng)我們第一參數(shù)是Array時(shí):

$.each(Array, function(key, value){
    this; // 這里的this和value一樣都是指向每次遍歷Array中的當(dāng)前元素
})

5、_This_ = TempMap[ this.id ] = This ? $.extend(this, _This_) : this;

這個(gè)里面包含兩個(gè)知識(shí)點(diǎn):

三目運(yùn)算符: let variable = a ? b : c 即: a 可以是任意可以轉(zhuǎn)換成boolean類(lèi)型的值或者運(yùn)算,如果a為true的話(huà),上式等同于let variable = b; 否則 上式等同于let variable = c;

a = b = c : 等同于 b = c, a = b(注:只有 a 是可以在這里聲明變量的)。

6、邏輯或( a || b )運(yùn)算的妙用

邏輯或運(yùn)算( a || b ),其中a、b可以是 boolean 類(lèi)型或者任意能轉(zhuǎn)換成 boolean 類(lèi)型的數(shù)據(jù)類(lèi)型或者運(yùn)算。在此段代碼中巧妙的運(yùn)用到了變量的初始化上。a || b 運(yùn)算的執(zhí)行過(guò)程,只有當(dāng) a 為 false 時(shí) 才會(huì)執(zhí)行 b, 只有 a 和 b 兩都是 false 會(huì)返回 false,否則返回a 或者 b,取決于 a 是否是true 或者是否可以轉(zhuǎn)換為true。

補(bǔ)充個(gè)基礎(chǔ)知識(shí):在 js 的邏輯判斷中 null, 0, undefined, "", "" 都可以轉(zhuǎn)換為 false。

四、思路分析

在 Array2Tree 函數(shù)作用域內(nèi)聲明一個(gè) TempMap 的變量名,用于每項(xiàng)數(shù)據(jù)引用的臨時(shí)存儲(chǔ)

使用 $.each() 函數(shù)對(duì) $.extend(true, [ ], arguments[0]) 得到的新數(shù)組進(jìn)行遍歷,$.each() 的第二個(gè)參數(shù)是一個(gè)匿名 function(){}, 我們?cè)?function(){} 里對(duì)每個(gè)數(shù)據(jù)進(jìn)行處理,最終放置到變量 TempMap 中

在 function 的作用域中,this 指向每次遍歷中 Array 的當(dāng)前元素。比如說(shuō)第一次進(jìn)入 function() 中的 this就是:{id :7, name: "豬", pid: 2}

var _This_ = TempMap[ this.id ];
// 尋找 TempMap 對(duì)象中 key 為 this.id 的對(duì)應(yīng)值。因?yàn)槊恳粋€(gè)數(shù)據(jù)的id是唯一的,所以這里的_This_得到的值只有兩種可能: undefined 或者 { children:[object ...] }(這種情況是由后面的代碼賦值而生成的)
_This_  = TempMap[ this.id ] =  _This_ ? $.extend( this, _This_ ) : this;

// 如果在 TempMap 中沒(méi)有找到 key 為 this.id 對(duì)應(yīng)的值,也就是 This = undefined 的情況,則把 this 直接賦值到 TempMap[ this.id ] 中去,并且讓 This 指向 this

// 如果找到了,就合并 This 到 this 對(duì)象上,然后再賦值給 TempMap[ this.id ],最后讓 This 指向 this。具體合并的效果可以看下面的例子:

$.extend({id: 4,  name: "雞",  pid: 1}, {children: {id: 13, name: "三黃雞", pid: 4}})
結(jié)果:{
    id: 4,  
    name: "雞",  
    pid: 1, 
    children: {
        id: 13, 
        name: "三黃雞", 
        pid: 4
      }
    }

重要:這一步保證當(dāng)前遍歷的元素之前的子元素能給 "穿" 到 TempMap[ this.id ] 上 ( ‘穿’ 理解成穿針引線一般的感覺(jué))。

this.pid = this.pid || 0; 

// 獲取當(dāng)前被遍歷的元素的 pid, 沒(méi)有 pid 的默認(rèn)為第一層,并賦予 this.pid = 0。這里不一定非得是0,只要能和別的id區(qū)分開(kāi)來(lái)就可以,這里采用0,是因?yàn)閿?shù)據(jù)庫(kù)的索引一般從1開(kāi)始計(jì)數(shù)。

var _Parent_ = TempMap[ this.pid ] = TempMap[ this.pid ] || { };

// 判斷 TempMap[ this.pid ] 是否是 undefined 。如果 TempMap[ this.pid ] 是 undefined,則 給TempMap[ this.pid ]賦值為{},并且把 Parent 初始化為 {}。否則 TempMap[ this.pid ] 不是 undefined時(shí),則把 Parent 指向 TempMap[ this.pid ]。

( _Parent_.children = _Parent_.children || [ ] ).push( _This_ );

// 因?yàn)橄啾榷再x值運(yùn)算的優(yōu)先級(jí)相對(duì)別的要低一些,所以采取 ( Parent_.children = _Parent_.children || [ ] ) 方式保證 _Parent_.children 始終不是 undefined,并且是 array 類(lèi)型。在這個(gè)條件下,我們把 _This 存進(jìn)_Parent_.children

重要:在這一步保證當(dāng)前遍歷的元素能被 ‘穿’ 到對(duì)應(yīng)的父元素上去。

return TempMap[ 0 ].children;

// 最終 TempMap 在本列中會(huì)變成如下形式:

![一個(gè) key 為 0, 1, ... 14, 15 的 Object][5]

而展開(kāi)之后,我們會(huì)發(fā)現(xiàn)想要的 ‘真正的樹(shù)’ 就是TempMap[ 0 ].children,效果見(jiàn)本文的第二張圖。那這又是什么樣的結(jié)構(gòu)呢?可以這么說(shuō) TempMap[ 0 ].children 是這棵樹(shù)結(jié)構(gòu)的整體,而其余的1 至 15 是每個(gè)對(duì)應(yīng)的this.id 的分支。

補(bǔ)充一點(diǎn):為什么在_Parent_.children賦值后,我們的TempMap[ this.pid ]也隨之改變,這里就涉及到引用數(shù)據(jù)的知識(shí)點(diǎn)了。在這里因?yàn)開(kāi)Parent_ = TempMap[ this.pid ],所以它們來(lái)指向同一個(gè)內(nèi)存空間,在_Parent_改變后,內(nèi)存空間中的值也就改變了,所以TempMap[ this.pid ]的值也就相應(yīng)的改變了。也正是引用類(lèi)型的數(shù)據(jù)的這個(gè)特點(diǎn),保證了我們的無(wú)論多少層的子元素都能被正確的 ‘穿’ 到了對(duì)應(yīng)的父元素上

五、總結(jié)

丈高樓始于平地,打好基礎(chǔ)知識(shí)異常重要!

文章出自 FCC(freeCodeCamp) 成都社區(qū),歡迎大家的加入,和我們一起討論、學(xué)習(xí)~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84439.html

相關(guān)文章

  • ( 第二篇 )仿寫(xiě)'Vue生態(tài)'系列___'模板小故事.'

    摘要:第二篇仿寫(xiě)生態(tài)系列模板小故事本次任務(wù)承上完成第一篇未完成的熱更新配置核心完成模板解析模塊的相關(guān)編寫(xiě)很多文章對(duì)模板的解析闡述的都太淺了本次我們一起來(lái)深入討論一下盡可能多的識(shí)別用戶(hù)的語(yǔ)句啟下在結(jié)構(gòu)上為雙向綁定等模塊的編寫(xiě)打基礎(chǔ)最終效果圖一模板頁(yè) ( 第二篇 )仿寫(xiě)Vue生態(tài)系列___模板小故事. 本次任務(wù) 承上: 完成第一篇未完成的熱更新配置. 核心: 完成模板解析模塊的相關(guān)編寫(xiě), ...

    wangtdgoodluck 評(píng)論0 收藏0
  • ( 第二篇 )仿寫(xiě)'Vue生態(tài)'系列___'模板小故事.'

    摘要:第二篇仿寫(xiě)生態(tài)系列模板小故事本次任務(wù)承上完成第一篇未完成的熱更新配置核心完成模板解析模塊的相關(guān)編寫(xiě)很多文章對(duì)模板的解析闡述的都太淺了本次我們一起來(lái)深入討論一下盡可能多的識(shí)別用戶(hù)的語(yǔ)句啟下在結(jié)構(gòu)上為雙向綁定等模塊的編寫(xiě)打基礎(chǔ)最終效果圖一模板頁(yè) ( 第二篇 )仿寫(xiě)Vue生態(tài)系列___模板小故事. 本次任務(wù) 承上: 完成第一篇未完成的熱更新配置. 核心: 完成模板解析模塊的相關(guān)編寫(xiě), ...

    ivydom 評(píng)論0 收藏0
  • '=='操作符小動(dòng)作

    摘要:相等操作符會(huì)有一個(gè)隱形的轉(zhuǎn)換,這個(gè)隱形的轉(zhuǎn)化會(huì)導(dǎo)致結(jié)果很奇怪。 [0] == true; // false [] == ![]; // true 相等操作符會(huì)有一個(gè)隱形的轉(zhuǎn)換,這個(gè)隱形的轉(zhuǎn)化會(huì)導(dǎo)致結(jié)果很奇怪。下面是隱形轉(zhuǎn)換的基本規(guī)則: 其中一個(gè)值是boolean值:兩個(gè)值都轉(zhuǎn)為數(shù)字,false轉(zhuǎn)為0,true轉(zhuǎn)為1 其中一個(gè)值是字符串,另一個(gè)是數(shù)字:都轉(zhuǎn)為數(shù)字再對(duì)比 其中一個(gè)是...

    PAMPANG 評(píng)論0 收藏0
  • ['1', '2', '3'].map(

    摘要:比如參數(shù)表示使用我們通常使用的十進(jìn)制數(shù)值系統(tǒng)。始終指定此參數(shù)可以消除閱讀該代碼時(shí)的困惑并且保證轉(zhuǎn)換結(jié)果可預(yù)測(cè)。當(dāng)未指定基數(shù)時(shí),不同的實(shí)現(xiàn)會(huì)產(chǎn)生不同的結(jié)果,通常將值默認(rèn)為。 showImg(https://segmentfault.com/img/bVbvtHZ?w=536&h=116); 為什么是[1,NaN,NaN]而不是[1,2,3]? 首先看下 Array.map()函數(shù)在MD...

    enali 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<