87 votes

Quelle est la meilleure façon (la plus efficace) de convertir toutes les clés d'un objet en minuscules?

Je suis arrivé à

function keysToLowerCase (obj) {
  var keys = Object.keys(obj);
  var n = keys.length;
  while (n--) {
    var key = keys[n]; // "cache" it, for less lookups to the array
    if (key !== key.toLowerCase()) { // might already be in its lower case version
        obj[key.toLowerCase()] = obj[key] // swap the value to a new lower case key
        delete obj[key] // delete the old key
    }
  }
  return (obj);
}

Mais je ne suis pas sûr du comportement de v8 à ce sujet, par exemple, va-t-il vraiment supprimer les autres clés ou va-t-il seulement supprimer les références et le garbage collector me posera-t-il un problème plus tard ?

Aussi, j'ai créé ces tests, j'espère que vous pourrez ajouter votre réponse là-bas pour voir comment elles se comparent.

ÉDIT 1: Apparemment, selon les tests, c'est plus rapide si nous ne vérifions pas si la clé est déjà en minuscules, mais mis à part le fait d'être plus rapide, est-ce que cela créera plus de désordre en ignorant cela et en créant simplement de nouvelles clés en minuscules ? Le garbage collector sera-t-il satisfait de cela ?

83voto

some Points 18965

La plus rapide que j'ai trouvée est si vous créez un nouvel objet :

var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
  key = keys[n];
  newobj[key.toLowerCase()] = obj[key];
}

Je ne suis pas assez familier avec le fonctionnement interne actuel de v8 pour vous donner une réponse définitive. Il y a quelques années, j'ai vu une vidéo où les développeurs parlaient d'objets, et de ce que je me souvienne, il supprimera simplement les références et laissera le ramasse-miettes s'en occuper. Mais c'était il y a des années donc même si c'était comme ça à l'époque, ça ne doit pas forcément être le cas maintenant.

Est-ce que cela vous posera un problème plus tard ? Cela dépend de ce que vous faites, mais probablement pas. Il est très courant de créer des objets à durée de vie courte afin que le code soit optimisé pour les gérer. Mais chaque environnement a ses limites, et cela pourrait éventuellement poser problème. Vous devez tester avec des données réelles.

40voto

caleb Points 586

Je utiliserais Lo-Dash.transform comme ceci:

var lowerObj = _.transform(obj, function (result, val, key) {
    result[key.toLowerCase()] = val;
});

39voto

Yves M. Points 1439

Utilisation de Object.fromEntries (ES10)

Solution native et immuable utilisant la nouvelle méthode Object.fromEntries:

const newObj = Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);

Jusqu'à ce que cette fonction soit largement disponible, vous pouvez la définir vous-même avec le polyfill suivant :

Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));

Un aspect intéressant est que cette méthode fait l'opposé de Object.entries, vous pouvez donc maintenant passer de l'objet à la représentation du tableau et vice versa.

37voto

Molomby Points 630

Personnellement, j'utiliserais :

let objectKeysToLowerCase = function (origObj) {
    return Object.keys(origObj).reduce(function (newObj, key) {
        let val = origObj[key];
        let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
        newObj[key.toLowerCase()] = newVal;
        return newObj;
    }, {});
}

C'est concis, récursif pour traiter les objets imbriqués et renvoie un nouvel objet plutôt que de modifier l'original.

Dans mes tests locaux limités, cette fonction est plus rapide que l'autre solution récursive actuellement répertoriée (une fois corrigée). J'aimerais faire des tests de performance par rapport aux autres, mais jsperf est actuellement hors service (???).

Elle est également écrite en ES5.1 donc, selon la documentation sur MDN, elle devrait fonctionner dans FF 4+, Chrome 5+, IE 9.0+, Opera 12+, Safari 5+ (donc, à peu près tout).

Vanilla JS for the win.

Je ne me préoccuperais pas trop de l'aspect de la récupération des déchets de tout cela. Une fois que toutes les références à l'ancien objet sont détruites, il sera récupéré par le GC mais le nouvel objet continuera à faire référence essentiellement à toutes ses propriétés, donc elles ne le seront pas.

Toutes les fonctions, les tableaux ou les expressions régulières seront "copiés" par référence. En termes de mémoire, même les chaînes de caractères ne seront pas dupliquées par ce processus car la plupart (toutes ?) des moteurs JS modernes utilisent l'internalisation des chaînes. Je pense que cela laisse juste les nombres, les booléens et les objets qui ont formé la structure originale à être récupérés par le GC.

Remarquez que (toutes les implémentations de) ce processus perdront des valeurs si l'original a plusieurs propriétés avec la même représentation en minuscules. Par exemple :

let myObj = { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' };
console.log(myObj);
// { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' }

let newObj = objectKeysToLowerCase(myObj);
console.log(newObj);
// { xx: 'one!' }

Bien sûr, parfois c'est exactement ce que vous voulez.

Mise à jour 2018-07-17

Quelques personnes ont remarqué que la fonction d'origine ne fonctionne pas bien avec les tableaux. Voici une version étendue et plus résiliente. Elle parcourt correctement les tableaux en profondeur et fonctionne si la valeur initiale est un tableau ou une valeur simple :

let objectKeysToLowerCase = function (input) {
    if (typeof input !== 'object') return input;
    if (Array.isArray(input)) return input.map(objectKeysToLowerCase);
    return Object.keys(input).reduce(function (newObj, key) {
        let val = input[key];
        let newVal = (typeof val === 'object') && val !== null ? objectKeysToLowerCase(val) : val;
        newObj[key.toLowerCase()] = newVal;
        return newObj;
    }, {});
};

10voto

Tom Roggero Points 2581

Version ES6 :

Object.keys(source)
  .reduce((destination, key) => {
    destination[key.toLowerCase()] = source[key];
    return destination;
  }, {});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X