84

我想出了

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

但是我不确定 v8 会如何处理它,例如,它真的会删除其他键还是只会删除引用并且垃圾收集器稍后会咬我?

另外,我创建了这些测试,我希望你可以在那里添加你的答案,这样我们就可以看到它们是如何匹配的。

编辑 1: 显然,根据测试,如果我们不检查密钥是否已经是小写字母,但速度更快,它会通过忽略这一点并创建新的小写密钥而造成更多混乱吗?垃圾收集器会对此感到满意吗?

4

20 回答 20

82

我想出的最快的方法是创建一个新对象:

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

我对 v8 的当前内部工作不够熟悉,无法给你一个明确的答案。几年前,我看到一个开发人员谈论对象的视频,而 IIRC 它只会删除引用并让垃圾收集器处理它。不过那是几年前的事了,就算当时是这样,现在也不需要这样了。

以后会咬你吗?这取决于你在做什么,但可能不是。创建短期对象是很常见的,因此代码经过优化以处理它。但是每个环境都有其局限性,也许它会咬你。您必须使用实际数据进行测试。

于 2012-09-22T04:07:38.000 回答
39

我会像这样使用Lo-Dash.transform

var lowerObj = _.transform(obj, function (result, val, key) {
    result[key.toLowerCase()] = val;
});
于 2014-08-13T15:23:37.203 回答
36

就个人而言,我会使用:

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

它简洁,重复处理嵌套对象并返回一个新对象而不是修改原始对象。

在我有限的本地测试中,这个函数比当前列出的其他递归解决方案更快(一旦修复)。我很想将它与其他人进行基准测试,但 jsperf 目前处于下降状态(???)。

它也是用 ES5.1 编写的,所以根据 MDN 上的文档,它应该可以在 FF 4+、Chrome 5+、IE 9.0+、Opera 12+、Safari 5+(所以,几乎所有东西)中工作。

Vanilla JS 获胜。

我不会太担心这一切的垃圾收集方面。一旦对旧对象的所有引用都被销毁,它将成为 GC,但对象仍将基本上引用它的所有属性,因此它们不会。

任何函数、数组或正则表达式都将通过引用被“复制”。在内存方面,即使是字符串也不会被这个过程复制,因为大多数(所有?)现代 JS 引擎都使用string interning。我认为只剩下构成原始结构的数字、布尔值和对象留给 GC 处理。

请注意,如果原始具有多个具有相同小写表示的属性,则此过程的(所有实现)将丢失值。IE:

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!' }

当然,有时这正是您想要的。

2018-07-17 更新

一些人注意到原始函数不适用于数组。这是一个扩展的、更有弹性的版本。如果初始值是数组或简单值,它会通过数组正确递归并工作:

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;
    }, {});
};
于 2016-12-10T05:45:24.533 回答
35

使用Object.fromEntries(ES10)

使用新Object.fromEntries方法的本机和不可变解决方案:


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

在该函数被广泛使用之前,您可以使用以下polyfill自己定义它:

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

一件好事是这个方法做的相反Object.entries,所以现在你可以在对象和数组表示之间来回切换。

于 2019-03-04T14:39:19.390 回答
10

ES6 版本:

Object.keys(source)
  .reduce((destination, key) => {
    destination[key.toLowerCase()] = source[key];
    return destination;
  }, {});
于 2018-07-29T05:26:27.000 回答
8

loDash/fp 方式,非常好,因为它本质上是一个内衬

import {
mapKeys
} from 'lodash/fp'

export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}
于 2017-04-07T16:31:50.280 回答
5

在我的测试中使用 forEach 似乎要快一些 - 并且原始参考已消失,因此删除新参考将使 gc 可以访问

function keysToLowerCase(obj){
    Object.keys(obj).forEach(function (key) {
        var k = key.toLowerCase();

        if (k !== key) {
            obj[k] = obj[key];
            delete obj[key];
        }
    });
    return (obj);
}

var O={一:1,二:2,三:3,四:4,五:5,六:{a:1,b:2,c:3,D:4,E:5}};keysToLowerCase(O);

/* 返回值:(对象)*/

{
    five:5,
    four:4,
    one:1,
    six:{
        a:1,
        b:2,
        c:3,
        D:4,
        E:5
    },
    three:3,
    two:2
}
于 2012-09-22T01:13:08.880 回答
3

这是将所有 json 键转换为小写的最简单解决方案。

let o = {"Account_Number   ":"0102301", "customer_NaME":"name"}

o = Object.keys(o).reduce((c, k) => (c[k.toLowerCase().trim()] = o[k], c), {})

console.log(o)
于 2020-03-26T08:59:48.087 回答
2

我使用了 ES6 和 TypeScript。 toLowerCaseObject函数将数组作为参数并递归地查看对象树并使每个节点小写:

function toLowerCaseObject(items: any[]) {
        return items.map(x => {
            let lowerCasedObject = {}
                for (let i in x) {
                    if (x.hasOwnProperty(i)) {
                        lowerCased[i.toLowerCase()] = x[i] instanceof Array ? toLowerCaseObject(x[i]) : x[i];
                    }
            }
            return lowerCasedObject;
        });
    }
于 2018-10-21T08:24:46.967 回答
2

简化答案

对于简单的情况,您可以使用以下示例将所有键转换为小写:

Object.keys(example).forEach(key => {
  const value = example[key];
  delete example[key];
  example[key.toLowerCase()] = value;
});

toUpperCase()您可以使用代替将所有键转换为大写toLowerCase()

Object.keys(example).forEach(key => {
  const value = example[key];
  delete example[key];
  example[key.toUpperCase()] = value;
});
于 2018-11-02T00:21:09.937 回答
2

单线(仅适用于顶级键):

Object.assign(...Object.keys(obj).map(key => ({[key.toLowerCase()]: obj[key]})))

转换:

{ a: 1, B: 2, C: { Z: 4 } }

到:

{ a: 1, b: 2, c: { Z: 4 } }
于 2019-12-01T21:49:30.767 回答
2

使用打字稿

/**
 * Lowercase the keys of an object
 * @example
  lowercaseKeys({FOO: true, bAr: false}); // {foo: true, bar: false}
 */
export function lowercaseKeys<T>(object: { [key: string]: T }): { [key: string]: T } {
  const result: { [key: string]: T } = {};

  for (const [key, value] of Object.entries(object)) {
    result[key.toLowerCase()] = value;
  }

  return result;
}

用法

lowercaseKeys({FOO: true, bAr: false}); // {foo: true, bar: false}
于 2020-10-27T15:53:09.707 回答
1

这不是最干净的方法,但它对我的团队有用,所以值得分享。

我创建了这个方法,因为我们的后端正在运行一种不区分大小写的语言,并且数据库和后端会产生不同的关键情况。对我们来说,它完美无缺。请注意,我们将日期作为字符串发送,我们不发送函数。

我们已将其简化为这一行。

const toLowerCase = (data) => JSON.parse(JSON.stringify(data).replace(/"([^"]+)":/g, ($0, key) => '"' + key.toString().toLowerCase() + '":'))

我们使用该JSON.parse(JSON.stringify(obj))方法克隆对象。这将生成 JSON 格式的对象的字符串版本。虽然对象是字符串形式,但您可以使用正则表达式,因为 JSON 是一种可预测的格式来转换所有键。

拆开是这样的。

const toLowerCase = function (data) {
  return JSON.parse(JSON.stringify(data)
   .replace(/"([^"]+)":/g, ($0, key) => {
     return '"' + key.toString().toLowerCase() + '":'
   }))
}
于 2018-08-14T16:21:02.820 回答
1
const keysToLowerCase = object => {
  return Object.keys(object).reduce((acc, key) => {
    let val = object[key];
    if (typeof val === 'object') {
      val = keysToLowerCase(val);
    }
    acc[key.toLowerCase()] = val;
    return acc;
  }, {});
};

适用于嵌套对象。

于 2020-08-17T12:52:30.770 回答
0

考虑只小写一次,将其存储在lowKeyvar 中:

function keysToLowerCase (obj) {
  var keys = Object.keys(obj);
  var n = keys.length;
  var lowKey;
  while (n--) {
    var key = keys[n];
    if (key === (lowKey = key.toLowerCase()))
    continue

    obj[lowKey] = obj[key]
    delete obj[key]

  }
  return (obj);
}
于 2012-09-22T00:30:29.177 回答
0

这是我基于上述示例之一的递归版本。

//updated function
var lowerObjKeys = function(obj) {
  Object.keys(obj).forEach(function(key) {
    var k = key.toLowerCase();
    if (k != key) {
      var v = obj[key]
      obj[k] = v;
      delete obj[key];

      if (typeof v == 'object') {
        lowerObjKeys(v);
      }
    }
  });

  return obj;
}

//plumbing
console = {
  _createConsole: function() {
    var pre = document.createElement('pre');
    pre.setAttribute('id', 'console');
    document.body.insertBefore(pre, document.body.firstChild);
    return pre;
  },
  info: function(message) {
    var pre = document.getElementById("console") || console._createConsole();
    pre.textContent += ['>', message, '\n'].join(' ');
  }
};

//test case
console.info(JSON.stringify(lowerObjKeys({
  "StackOverflow": "blah",
  "Test": {
    "LULZ": "MEH"
  }
}), true));

请注意,它不跟踪循环引用,因此您最终可能会出现无限循环,从而导致堆栈溢出。

于 2015-07-12T17:12:15.460 回答
0

对于所有值:

to_lower_case = function(obj) {
    for (var k in obj){
        if (typeof obj[k] == "object" && obj[k] !== null)
            to_lower_case(obj[k]);
        else if(typeof obj[k] == "string") {
            obj[k] = obj[k].toLowerCase();
        }
    }
    return obj;
}

同样可以用于稍作调整的键。

于 2018-09-01T13:37:41.967 回答
0

我就是这样做的。我的输入可以是任何东西,它通过嵌套对象和对象数组回避。

const fixKeys = input => Array.isArray(input)
  ? input.map(fixKeys)
  : typeof input === 'object'
  ? Object.keys(input).reduce((acc, elem) => {
      acc[elem.toLowerCase()] = fixKeys(input[elem])
      return acc
    }, {})
  : input

使用 mocha 测试

const { expect } = require('chai')

const fixKeys = require('../../../src/utils/fixKeys')

describe('utils/fixKeys', () => {
  const original = {
    Some: 'data',
    With: {
      Nested: 'data'
    },
    And: [
      'an',
      'array',
      'of',
      'strings'
    ],
    AsWellAs: [
      { An: 'array of objects' }
    ]
  }

  const expected = {
    some: 'data',
    with: {
      nested: 'data'
    },
    and: [
      'an',
      'array',
      'of',
      'strings'
    ],
    aswellas: [{ an: 'array of objects' }]
  }

  let result

  before(() => {
    result = fixKeys(original)
  })

  it('left the original untouched', () => {
    expect(original).not.to.deep.equal(expected)
  })

  it('fixed the keys', () => {
    expect(result).to.deep.equal(expected)
  })
})
于 2019-06-18T08:03:56.727 回答
0
var aa = {ID:1,NAME:'Guvaliour'};
var bb= {};
var cc = Object.keys(aa);
cc.forEach(element=>{
 bb[element.toLowerCase()]=aa[element];
});
cosole.log(bb)
于 2019-07-28T03:16:01.597 回答
0

下面的代码将所有键转换为小写

array.forEach(item=>{
         
          let data = Object.keys(item).reduce((result, p) => (result[p.toLowerCase().trim()] = item[p], result), {})
          
          if(data.hasOwnProperty(fieldname)){
              if(data[fieldname]){
                if(!response['data'].includes(data[fieldname].toLowerCase()))
                    response['data'].push(data[fieldname]) 
                
             }
           }
          
        })
于 2020-07-01T06:00:19.777 回答