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;
}, {});
};