la compression des hiérarchies d'objets en JavaScript
-
12-09-2019 - |
Question
Y at-il une approche générique de « compression » des objets imbriqués à un seul niveau:
var myObj = {
a: "hello",
b: {
c: "world"
}
}
compress(myObj) == {
a: "hello",
b_c: "world"
}
Je suppose qu'il y aurait un peu impliqué récursion, mais je pensais que je ne ai pas besoin de réinventer la roue ici ...!?
La solution
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:
-
Les objets récursifs ne fonctionneront pas. Par exemple:
var o = { a: "foo" }; o.b = o; flatten(o);
sera récursif jusqu'à ce qu'il lève une exception.
-
Comme la réponse de ruquay, ce tire les éléments du tableau, tout comme les propriétés des objets normaux. Si vous voulez garder les tableaux intacts, ajoutez "
|| prop instanceof Array
" des exceptions. -
Si vous appelez cela sur des objets à partir d'une autre fenêtre ou un cadre, les dates et les expressions régulières ne seront pas inclus, puisque
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]"
Autres conseils
Voici un rapide, mais attention, b / c il sera pas travail w / tableaux et des valeurs nulles (b / c leurs déclarations typeof "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);
Voici un rapide CoffeeScript version basée off Matthew Crumley (je ne l'ai pas utiliser 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'utiliser ces fonctions pour pousser des graphes d'objets dans Redis HASHES , qui soutiennent un seul profondeur de paires clé / valeur.