2009-06-08 2 views
10

Есть общий подход к «сжатие» вложенных объектов на одном уровне:сжимающие объект иерархии в JavaScript

var myObj = { 
    a: "hello", 
    b: { 
     c: "world" 
    } 
} 

compress(myObj) == { 
    a: "hello", 
    b_c: "world" 
} 

Я предполагаю, что будет какая-то рекурсия участие, но я полагал, что не нужно изобретать колесо здесь ...!?

+0

Зачем вам это нужно? Вы хотите обработать ваши javascripts во время сборки, а затем производительность js будет улучшена? Но как бы вы могли получить доступ к вложенным объектам из js (после сжатия), если вам нужно работать со сложной объектной моделью (где, например, подобъект (вложенный объект) должен проходить как аргумент некоторой функции)? –

+1

Мне нужно это для отображения данных, где обработка не обрабатывает вложенные объекты. – AnC

+0

У меня была аналогичная потребность в AnC при использовании вложенных объектов с помощью [Redis] (http://redis.io/commands#hash), поскольку она поддерживает только плоские хэши. Я закончил с использованием [CoffeeScript-версии] (http://stackoverflow.com/questions/963607/compressing-object-hierarchies-in-javascript/6940124#6940124) из [решения Мэтью Крамли] (http://stackoverflow.com/вопросы/963607/сжатия-объектные иерархии-в-JavaScript/965315 # 965315). –

ответ

21
function flatten(obj, includePrototype, into, prefix) { 
    into = into || {}; 
    prefix = prefix || ""; 

    for (var k in obj) { 
     if (includePrototype || obj.hasOwnProperty(k)) { 
      var prop = obj[k]; 
      if (prop && typeof prop === "object" && 
       !(prop instanceof Date || prop instanceof RegExp)) { 
       flatten(prop, includePrototype, into, prefix + k + "_"); 
      } 
      else { 
       into[prefix + k] = prop; 
      } 
     } 
    } 

    return into; 
} 

Вы можете включать в себя элементы унаследованных членов пропускания true в качестве второго параметра.

Несколько предостережений:

  • рекурсивные объекты не будут работать. Например:

    var o = { a: "foo" }; 
    o.b = o; 
    flatten(o); 
    

    будет возвращаться до тех пор, пока оно не выберет исключение.

  • Как ответ ruquay, это вытаскивает элементы массива так же, как и обычные свойства объекта. Если вы хотите сохранить массивы без изменений, добавьте «|| prop instanceof Array» к исключениям.

  • Если вы вызываете это на объекты из другого окна или кадра, даты и регулярные выражения не будут включены, так как instanceof не будет работать должным образом. Вы можете исправить, заменив его методом на ToString по умолчанию, как это:

    Object.prototype.toString.call(prop) === "[object Date]" 
    Object.prototype.toString.call(prop) === "[object RegExp]" 
    Object.prototype.toString.call(prop) === "[object Array]" 
    
+0

Вау, похоже, отлично работает! Спасибо, куча, также за подробную документацию - я очень ценю это! – AnC

4

Вот быстрый, но смотрите, b/c будет не Работа с массивами и значениями null (b/c их тип возвращает «объект»).

var flatten = function(obj, prefix) { 
    if(typeof prefix === "undefined") { 
    prefix = ""; 
    } 
    var copy = {}; 
    for (var p in obj) { 
    if(obj.hasOwnProperty(p)) { 
     if(typeof obj[p] === "object") { 
     var tmp = flatten(obj[p], p + "_"); 
     for(var q in tmp) { 
      if(tmp.hasOwnProperty(q)) { 
      copy[prefix + q] = tmp[q]; 
      } 
     } 
     } 
     else { 
     copy[prefix + p] = obj[p]; 
     } 
    } 
    } 
    return copy; 
} 

var myObj = { 
    a: "level 1", 
    b: { 
    a: "level 2", 
    b: { 
     a: "level 3", 
     b: "level 3" 
    } 
    } 
} 

var flattened = flatten(myObj); 
+0

Спасибо за это. Он еще не работает (см. Тестовый объект ниже); будет копаться в нем и сообщать о любом прогрессе здесь. (Как уже упоминалось выше, я ожидал, что это решаемая проблема - то есть, что бы готовая функция в некоторой JavaScript поваренной книги ...) вар myObj = { \t a1: «Уровень 1», \t a2: { \t \t b1: 99, \t \t b2: { \t \t \t c1: новые Дата(), \t \t \t c2: "уровень 3" \t \t}, \t \t b3: "ASD" \t}, \t а3:/Foo/ }; – AnC

2

Вот быстрый CoffeeScript версия, основанная от Matthew Crumley's answer (я не использовал includePrototype, как у меня не было никакой потребности в ней):

flatten = (obj, into = {}, prefix = '', sep = '_') -> 
    for own key, prop of obj 
    if typeof prop is 'object' and prop not instanceof Date and prop not instanceof RegExp 
     flatten prop, into, prefix + key + sep, sep 
    else 
     into[prefix + key] = prop 
    into 

и основная unflatten версия, которая, несомненно, потерпит неудачу с повторными сепараторов и других подобных trickiness:

unflatten = (obj, into = {}, sep = '_') -> 
    for own key, prop of obj 
    subKeys = key.split sep 
    sub = into 
    sub = (sub[subKey] or= {}) for subKey in subKeys[...-1] 
    sub[subKeys.pop()] = prop 
    into 

FWIW, я использую эти функции для точечного отображения графов объектов в Redis hashes, которые поддерживают только одну пару пар ключ/значение.

Смежные вопросы