2009-06-08 21 views
10

¿Hay un enfoque genérico para "comprimir" objetos anidados a un solo nivel:compresión jerarquías de objetos de JavaScript

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

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

supongo que habría algún recursividad involucrados, pero pensé que no necesito reinventar la rueda aquí ...!?

+0

¿Por qué necesitarías eso? ¿Desea procesar sus javascripts durante el tiempo de compilación y luego se mejorará el rendimiento de js en tiempo de ejecución? Pero, ¿cómo accedería a los objetos anidados desde su js (después de la compresión) si necesita operar con un modelo de objetos complejo (donde, por ejemplo, subobjeto (objeto anidado) tiene que pasar como argumento para alguna función)? –

+1

Necesito esto para una asignación de datos donde el procesamiento no maneja objetos anidados. – AnC

+0

Tenía una necesidad similar a AnC al usar objetos anidados con [Redis] (http://redis.io/commands#hash) ya que solo admite hash planos. Terminé usando una [versión de CoffeeScript] (http://stackoverflow.com/questions/963607/compressing-object-hierarchies-in-javascript/6940124#6940124) de [la solución de Matthew Crumley] (http://stackoverflow.com/questions/963607/compressing-object-hierarchies-in-javascript/965315 # 965315). –

Respuesta

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; 
} 

Puede incluir miembros heredados miembros pasando true en el segundo parámetro.

algunas advertencias:

  • objetos recursivos no funcionará. Por ejemplo:

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

    se repetirán hasta que arroje una excepción.

  • Al igual que la respuesta de ruquay, esto extrae los elementos de la matriz al igual que las propiedades normales del objeto. Si desea mantener las matrices intactas, agregue "|| prop instanceof Array" a las excepciones.

  • Si llama esto a objetos de una ventana o marco diferente, las fechas y las expresiones regulares no se incluirán, ya que instanceof no funcionarán correctamente. Se puede arreglar eso sustituyéndolo por el método toString por defecto de esta manera:

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

¡Guau, parece que funciona genial! Muchas gracias, también por la documentación detallada. ¡Realmente lo aprecio! – AnC

4

He aquí uno rápido, pero ojo, b/c no funciona con matrices y valores nulos (b/c su typeof devuelve "objeto").

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

Gracias por esto. Todavía no funciona del todo (ver el objeto de prueba a continuación); profundizará en él e informará cualquier progreso aquí. (Como se mencionó antes, esperaba que esto era un problema resuelto - es decir, que no habría una función ya hechas en algún libro de cocina JavaScript ...) var = {myObj \t a1: "Nivel 1", \t a2: { \t \t b1: 99, \t \t b2: { \t \t \t c1: new Date(), \t \t \t c2: "nivel 3" \t \t}, \t \t B3: "asd" \t}, \t a3:/foo/ }; – AnC

2

Aquí está basada una versión rápida CoffeeScript fuera Matthew Crumley's answer (yo no uso includePrototype ya que no tenía necesidad de él):

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 

y una versión básica unflatten, lo que sin duda fallar con repetidos separadores y otros tales astucia:

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, utilizo estas funciones para insertar gráficos de objetos en Redis hashes, que solo admiten una profundidad única de pares clave/valor.

Cuestiones relacionadas