如何最有效地将对象的所有键转换为小写?

101

我想出了一个

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: 根据测试结果,如果不检查键名是否已经转换成小写,速度会更快,但除了速度更快之外,忽略这一步骤并创建新的小写键名是否会导致更多混乱?垃圾回收器是否会满意?


2
你能否创建一个新对象而不是修改现有的对象?这样你就可以跳过所有的删除操作。 - Jason Orendorff
@JasonOrendorff 显然它更慢,每次都会创建一个不必要的对象,垃圾收集器对此也不会满意... - João Pinto Jerónimo
很不幸,你的测试是错误的。SETUP部分仅在每个时钟循环中运行一次。由于你在设置中声明了对象,因此只有第一个测试的第一次迭代实际上将对象键更改为小写字母,所有其他迭代都会得到一个键已经为小写字母的对象。在[10]版本中修复(http://jsperf.com/object-keys-to-lower-case/10)。(大约一小时前我发表了类似的评论,我说它只运行一次。我注意到那是错误的,所以我删除了我的评论并进行了更多测试) - some
@一些人 我认为JasonOrendorff在第7版中进行了更正,我添加了一个不缓存键名的函数,一切都非常接近(对我来说,[1014、1080、1008]):http://jsperf.com/object-keys-to-lower-case/11 - João Pinto Jerónimo
@JoãoPintoJerónimo key.toLowerCase() 被调用了两次,你可以将其存储在一个变量中,并在下一行中使用它。而且创建一个新对象,只是添加新键比:添加新键到原始对象+删除先前的键更慢,这很奇怪? - S.Serpooshan
显示剩余4条评论
24个回答

3

使用TypeScript

/**
 * 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}

3

一句话概括(仅适用于顶层键):

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

这会创建一个包含所有属性的数组? - worldwildwebdev
刚刚更新了代码。它将把所有顶层键转换为小写。 - giladb

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

2
这不是最干净的方法,但对于我的团队有效,所以值得分享。
我创建了这个方法,因为我们的后端运行的语言不区分大小写,数据库和后端会产生不同的键名大小写。对我们来说,它一直运作得很完美。请注意,我们将日期作为字符串发送,而不发送函数。
我们已将其简化为这一行代码。
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() + '":'
   }))
}

1
const newObj = {};

for(const key in obj){
    newObj[key.toLowerCase()] = obj[key];
}

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

适用于嵌套对象。


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

同样的方法可以用于带有微小调整的键。


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

0
考虑仅将大小写转换一次,并将其存储在名为 lowKey 的变量中:
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);
}

添加到版本6:http://jsperf.com/object-keys-to-lower-case/6 我认为它并不更快 - João Pinto Jerónimo

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

注意,它不会跟踪循环引用,因此可能会导致无限循环并导致堆栈溢出。


这里有一个 bug;函数只在 if (k != key) 的情况下递归,因此如果你在小写键中存储了一个嵌套对象,它将不会被处理。修复方法是将内部的 if (typeof v == 'object') { ... } 子句移动到外部的 if (k != key) { ... } 子句之外。性能看起来差不多。 - Molomby
哦,还有 var v = obj[key] 的赋值,这确实会降低性能.. :/ - Molomby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接