2009-06-08 8 views
10

Y at-il une approche générique de « compression » des objets imbriqués à un seul niveau:hiérarchies objet comprimant dans JavaScript

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

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

Je suppose qu'il y aurait une récursion impliqué, mais je me suis dit que je ne ai pas besoin de réinventer la roue ici ...!?

+0

Pourquoi auriez-vous besoin de cela? Souhaitez-vous traiter vos javascripts pendant la compilation, puis les performances de js seront améliorées? Mais comment accèderiez-vous aux objets imbriqués à partir de votre js (après compression) si vous devez opérer avec un modèle d'objet complexe (où par exemple subobject (objet imbriqué) doit passer en argument à une fonction)? –

+1

J'ai besoin de cela pour un mappage de données où le traitement ne gère pas les objets imbriqués. – AnC

+0

J'avais un besoin similaire à AnC lors de l'utilisation d'objets imbriqués avec [Redis] (http://redis.io/commands#hash) car il ne supporte que les hachages plats. J'ai fini par utiliser une [version de CoffeeScript] (http://stackoverflow.com/questions/963607/compressing-object-hierarchies-in-javascript/6940124#6940124) de [la solution de Matthew Crumley] (http://stackoverflow.com/questions/963607/compression-object-hierarchies-in-javascript/965315 # 965315). –

Répondre

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

Vous pouvez inclure des membres hérités des membres en passant true dans le second paramètre.

Quelques mises en garde:

  • objets récursifs ne fonctionnera pas. Par exemple:

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

    se recurera jusqu'à ce qu'il déclenche une exception.

  • Comme la réponse de ruquay, cela extrait les éléments du tableau tout comme les propriétés normales de l'objet. Si vous souhaitez conserver les tableaux intacts, ajoutez "|| prop instanceof Array" aux exceptions.

  • Si vous appelez ceci sur des objets d'une fenêtre ou d'un cadre différent, les dates et expressions régulières ne seront pas incluses, car instanceof ne fonctionnera pas correctement. Vous pouvez résoudre ce problème en remplaçant par la méthode toString par défaut comme ceci:

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

Wow, cela semble bien fonctionner! Merci beaucoup, aussi pour la documentation détaillée - j'apprécie vraiment! – AnC

4

Voici un rapide, mais attention, il pas travail w/tableaux et valeurs null (b/c leur typeof renvoie "objet").

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

Merci pour ça. Cela ne fonctionne pas encore complètement (voir l'objet de test ci-dessous); va creuser dedans et signaler tout progrès ici. (Comme mentionné précédemment, je pensais que c'était un problème résolu - à-dire qu'il y aurait une fonction ready-made dans une livre de cuisine JavaScript ...) var myObj = { \t a1: "niveau 1", \t a2: { \t \t b1: 99, \t \t b2: { \t \t \t c1: new date(), \t \t \t c2: "niveau 3" \t \t}, \t \t b3: "asd" \t}, \t a3:/foo/ }; – AnC

2

Voici une version CoffeeScript rapide basée hors Matthew Crumley's answer (je n'ai pas utilisé includePrototype comme je l'avais pas besoin pour cela):

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 

et une version Redresser de base, ce qui serait sans doute échouer avec des séparateurs répétés et d'autres tels rouerie:

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, j'utilise ces fonctions pour pousser les graphiques d'objet dans Redis hashes, qui ne supportent qu'une seule profondeur de paires clé/valeur.

Questions connexes