2014-07-22 85 views
0

遞歸和關閉scope`我想以一個扁平化的對象,要做到這一點,我用這個函數:無法理解`這個壓扁對象

var flatter = function(ob){ 
    var f = {}; 
    for(var i in ob) { 
     if(typeof ob[i] == 'object') { 
      var newOb = flatter(ob[i]); 
      for(var x in newOb) { 
       f[i+'.'+x] = newOb[x]; 
      } 
     }else{ 
      f[i] = ob[i]; 
     } 
    } 
    return f; 
} 

工作正常。我得到正確的結果應用此對象:

var ob = { 
    "address" : { 
     "details" : { 
      "first" : "siva", 
      "last" : "sankara", 
      "mam":["mam1","mam2"] 
     } 
    } 
}; 

結果是:

reslut : Object {address.details.first: "siva", address.details.last: "sankara", address.details.mam.0: "mam1", address.details.mam.1: "mam2"} 

但我不能夠理解我是多麼得到的結果。我明白,這是面向recursionclosure scope - 但seaching谷歌我沒有得到任何明確的教程或文章。

任何人都能幫助我理解這一步嗎?

Here is the live demo

在此先感謝!

回答

1
function flatter(ob){ 
    'use strict'; 
    var f = {}, //return this 
     key; 
    for(key in ob) { //for each key 
     if (ob.hasOwnProperty(key)) { 
      if(typeof ob[key] === 'object') { //if value is object 
       //flatten this object again. Assign result to newOb 
       var newOb = flatter(ob[key]); 
       for(var x in newOb) { 
        f[key + '.' + x] = newOb[x]; 
       } 
      } else { 
       f[key] = ob[key]; 
      } 
     } 
    } 
    return f; 
} 

你可以像

function flatter(ob){ 
    'use strict'; 
    var f = {}, //return this object 
     key; 
    for(key in ob) { //for each key 
     if (ob.hasOwnProperty(key)) { 
      if(typeof ob[key] === 'object') { //if value is object 
       var newOb = (function (ob) { 
        'use strict'; 
        var f = {}, //return this object 
         key; 
        for(key in ob) { //for each key 
         if (ob.hasOwnProperty(key)) { 
          if(typeof ob[key] === 'object') { //if value is object 
           var newOb = flatter(ob[key]); 
           for(var x in newOb) { 
            f[key + '.' + x] = newOb[x]; 
           } 
          } else { 
           f[key] = ob[key]; 
          } 
         } 
        } 
        return f; 
       }(ob[key])); 
       for(var x in newOb) { 
        f[key + '.' + x] = newOb[x]; 
       } 
      } else { 
       f[key] = ob[key]; 
      } 
     } 
    } 
    return f; 
} 

主要思想的東西翻譯這個代碼是每一個函數調用該函數的身體來代替。
對象本身是一個遞歸結構,因爲可以內容對象。如果給出

{ 
    id: 12345, 
    name: 'John', 
    friends: [12346, 75645, 96768] 
} 

遞歸是不需要的。對象不包含任何對象,所以它可以在沒有額外的函數調用的情況下(通過平坦的方式)被拉長。如果給出

{ 
    id: 12345, 
    name: { 
     first: 'John', 
     last: 'Doe' 
    }, 
    friends: [12346, 75645, 96768] 
} 

然後對象包含對象作爲字段。所以你可以使用函數調用被函數體替換的函數。如果給出

{ 
    id: 12345, 
    name: { 
     first: 'Helen', 
     last: { 
      beforeMarriage: 'Dobsky', 
      afterMarriage: 'Bobsky' 
     } 
    }, 
    friends: [12346, 75645, 96768] 
} 

然後一個不能沒有3個函數調用。所以你可以複製三次函數體。但是,對象可以有[無限]非常深的結構。所以函數的嵌套體的數量是未知的。因此,不是將函數體嵌套到函數中,而是使用遞歸調用。
遞歸函數應至少有一個出口點,以避免無限遞歸

return f; 
在我們的例子

。這個出口點可以達到,因爲對象中的字段數量是有限的。這不是解決任務的唯一方法。由於對象看起來像樹(一種)遞歸可以用堆棧來代替,這可以保留複雜的字段,並且在處理簡單的字段後返回到堆棧對象並在循環中對待它們。

堆棧實現。不漂亮,但作品)

function iflatter(input) { 
    'use strict'; 
    var f = {}, //return this object 
     key, 
     stack = [], 
     ob, 
     prefix, 
     name; 
    stack.push(["", input]); 
    while (stack.length != 0) { 
     [prefix, ob] = stack.pop(); 
     for(key in ob) { //for each key 
      if (ob.hasOwnProperty(key)) { 
       if (prefix !== "") { 
        name = prefix + "." + key; 
       } else { 
        name = key; 
       } 
       if(typeof ob[key] === 'object') { 
        stack.push([name, ob[key]]); 
       } else { 
        f[name] = ob[key]; 
       } 
      } 
     } 
    } 
    return f; 
} 
0

您正在傳遞一個對象到flatter()。當對象具有屬性值爲Object的屬性時,它將再次或遞歸地將該對象傳遞給flatter()。請參閱if(typeof ob[i] == 'object')?這意味着如果ob具有屬性i並且其值(獲得爲ob[i])是對象。注var flatter = function(){}相當於function flatter(){}