2014-01-10 26 views
4

我有一個嵌套數組的對象的複雜數組。下面的工作提取某些對象,但這是我寫的最醜陋的事情之一。Javascript:改進四個嵌套循環?

有沒有一些JavaScript黑暗的魔術來做到這一點優雅?

function getEighthInsertionBlocks() { 
    var struct = Lifestyle.Pagination.structure; 
    var blocks = []; 
    for (var i = 0; i<struct.length; i++) { 
     var page = struct[i]; 
     var layers = page.children; 
     for (var j=0; j<layers.length; j++) { 
      var layer = layers[j]; 
      if (layer.className === 'EighthPageLayer') { 
       var rows = layer.children; 
       for (var k=0; k<rows.length; k++) { 
        var row = rows[k]; 
        eBlocks = row.children; 
        for (var l=0; l<eBlocks.length; l++) { 
         blocks.push(eBlocks[l]); 
        } 
       } 
      } 
     } 
    } 

    return blocks; 
} 

不是說我是代碼高爾夫的忠實粉絲,但是......這太可怕了。

+1

你完全相同。 – tenub

+0

只是一個想法,它可能更易於使用foreach循環代替 – RyanS

+1

提取每個循環到一個方法? –

回答

0

我通常傾向於喜歡使用forEach爲可讀性,但這是主觀的。

function isEighthPageLayer(layer){ 
    return layer.className === "EighthPageLayer" 
} 

function getEighthInsertionBlocks(struct) { 
    var blocks = []; 
    struct.forEach(function(page){ 
     page.layers 
      .filter(isEighthPageLayer) 
      .forEach(function(layer) { 
       layer.children.forEach(function(row){ 
        row.children.forEach(function(eBlocks){ 
         blocks.push(eBlocks); 
        }); 
       }); 
      }); 
     }); 
    }); 
    return blocks; 
} 
+0

當然,目標是從過濾器forEach中提取一些函數。我認爲最好的候選人是具有圖層參數的函數。我發出警告。 – farvilain

+0

@Carth是的,爲我學習英語的時間: -/ – farvilain

+0

@farvilian您可以將傳遞給'forEach'的函數提取到變量中,這將是一個非常優雅的解決方案 – Stephen

3

你可以寫一個通用的迭代,這將減少代碼分成順序塊:

var iterator = function(collection, callback){ 
    var length = collection.length; 
    var results = []; 
    var result; 
    for (var i = 0; i < collection.length; i++){ 
     result = callback(colleciton[i], i); 
     if (result){ 
      results = results.concat(result); 
     } 
    } 
    return results; 
}; 

function getEighthInsertionBlocks() { 
    var struct = Lifestyle.Pagination.structure; 
    var layers = iterator(struct, function(page){ return page.children; }); 
    var rows = iterator(layers, function(layer){ 
     return layer.className === 'EighthPageLayer' ? layer.children : null; 
    }); 
    return iterator(rows, function(eBlocks, index){ return eblocks[index]; }); 
} 
+1

太棒了! :)比我的好! – farvilain

+0

爲了這個工作,我們需要連接結果,而不是推送它們。否則,我們正在有效地實現'Array.prototype.map'。 – Peter

+0

@彼得我不確定我遵循你的邏輯。這工作沒有concat。另外,'Array.prototype.map'沒有IE8的支持(如果需要的話)。 – Stephen

0

這是一個有趣的挑戰。爲了避免深層嵌套,您需要一個可以遞歸使用的泛型迭代器,但迭代中還有一些特殊情況。所以,我試圖創建一個通用迭代器,您可以傳遞一個選項對象以指定特殊條件。這是我想出來的。因爲我沒有一個簡單的數據集,這是未經測試,但希望你看到的想法:

function iterateLevel(data, options, level, output) { 
    console.log("level:" + level); 
    console.log(data); 
    var fn = options[level] && options[level].fn; 
    for (var i = 0; i < data.length; i++) { 
     if (!fn || (fn(data[i]) === true)) { 
      if (level === options.endLevel) { 
       output.push(data[i]); 
      } else { 
       iterateLevel(data[i].children, options, level + 1, output); 
      } 
     } 
    } 
} 

var iterateOptions = { 
    "1": { 
     fn: function(arg) {return arg.className === 'EighthPageLayer'} 
    }, 
    "endLevel": 3 
} 
var blocks = []; 
iterateLevel(Lifestyle.Pagination.structure, iterateOptions, 0, blocks); 

的想法是,選擇對象可以爲每個級別上可選的過濾功能,它告訴你如何許多層面都要下去。

工作演示:http://jsfiddle.net/jfriend00/aQs6h/