将对象的所有按键都变为小写的最佳方式(最有效)是什么? [英] What's the best way (most efficient) to turn all the keys of an object to lower case?

查看:114
本文介绍了将对象的所有按键都变为小写的最佳方式(最有效)是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



 函数keysToLowerCase(obj){
var keys = Object.keys( OBJ);
var n = keys.length;
while(n--){
var key = keys [n]; (key!== key.toLowerCase()){//可能已经是其小写形式的版本了
obj [key.toLowerCase( )] = obj [key] //将该值交换为新的小写键
delete obj [key] //删除旧键
}
}
return(obj );
}

但我不确定v8会如何表现,例如,它会真的删除其他键还是只会删除引用和垃圾收集器会咬我以后?



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



编辑1:
显然,根据测试,如果我们不检查密钥是否已经小写,被抛开更快,它会忽略这一点并创建新的小写键来创建更多的混乱?垃圾收集器会对此感到满意吗?

最快的我想出的是如果你创建一个新的对象:

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

我对v8的当前内部工作并不熟悉,一个明确的答案。几年前,我看到一个视频,开发人员谈论对象,而IIRC
只会删除引用并让垃圾收集器处理它。但几年前,所以即使是那样的话,现在也不需要那样。



晚些时候会咬你吗?这取决于你在做什么,但可能不是。创建短生命周期的对象是非常常见的,所以代码被优化来处理它。但是每个环境都有其局限性,也许它会咬你。你必须用实际数据进行测试。

2017年更新

新增了一个实用功能,对象的深层副本,支持循环引用。

  / ** @summary objectKeysToLowerCase(input,deep,filter)
*返回a将所有自己的键转换为小写的新对象。
*副本可以很浅(默认)或较深。
*
*在深拷贝期间支持循环引用,并且输出将具有
*相同的结构。
*
*默认情况下只复制具有Object作为构造函数的对象。
*可以使用过滤器功能进行更改。
*
*注意:如果一个对象具有仅在大小写不同的多个键,则
*只保存上次看到的键的值。该订单通常是
*,其顺序是按键创建的。
* Exaple:input = {aa:1,aA:2,aa:3,AA:4},output = {aa:4};
*
*注意:要检测循环引用,会为每个新对象搜索已经转换
*的对象列表。如果你有太多的对象,它会
*变得越来越慢...
*
* @param {object} input
*源对象
* @param {boolean | number} deep
*如果deep为undefined,null,false或0,则进行浅拷贝。
*如果deep为真或为正数。
*该数字指定要复制的级别。无限是一个有效的数字。
*此变量在深拷贝期间内部使用。
* @param {function}过滤
*过滤函数(对象)过滤应该复制的对象。
*如果它返回true,则执行复制。
* @returns {object}
*
* /
function objectKeysToLowerCase(input,deep,filter){
var idx,key,keys,last,output,自我,类型,价值;
self = objectKeysToLowerCase;
type = typeof deep;

//将deep转换为0到Infinity之间的数字或保留特殊对象。
if(type ==='undefined'|| deep === null || deep === 0 || deep === false){
deep = 0; //浅的副本
}
else if(type ==='object'){
if(!(deep instanceof self)){
throw new TypeError('Expected'深成为一个特殊对象);
}
}
else if(deep === true){
deep = Infinity; //深度复制
}
else if(type ==='number'){
if(isNaN(deep)|| deep <0){
throw new RangeError (
'预计深为正数,得到'+深
);
}
}
else抛出新的TypeError(
'Expecteddeep为布尔值,数字或对象,得到''+ type +'''
);


//检查输入的类型,如果为null或不是对象则抛出。
if(input === null || typeof input!=='object'){
throw new TypeError('Expected'input'to be a object');
}

//检查过滤器类型
type = typeof filter;
if(filter === null || type ==='undefined'|| type ==='function'){
filter = filter ||空值;
} else {
抛出新的TypeError('Expected'filter''作为函数');
}

keys = Object.keys(input); //从对象获取自己的密钥
last = keys.length - 1;
output = {}; //新对象

if(deep){//只在需要时运行深层副本。
if(typeof deep ==='number'){
//创建在深拷贝过程中使用的特殊对象
deep =
Object.seal(
Object .create(
self.prototype,
{
input:{value:[]},
output:{value:[]},
level:{value :-1,writable:true},
max:{value:deep,writable:false}
}

);
} else {
//圆检测
idx = deep.input.indexOf(input);
if(〜idx){
return deep.output [idx];
}
}

deep.level + = 1;
deep.input.push(输入);
deep.output.push(输出);

idx = last + 1;
while(idx--){
key = keys [last - idx]; //使用[last - idx]保存顺序。
value = input [key]; (b)if(typeof value ==='object'&& value&&& deep.level< deep.max){
if(filter?filter(value):value.constructor = == Object){
value = self(value,deep,filter);
}
}
output [key.toLowerCase()] = value;
}
deep.level - = 1;
} else {
//简单浅拷贝
idx = last + 1;
while(idx--){
key = keys [last - idx]; //使用[last - idx]保存顺序。
output [key.toLowerCase()] = input [key];
}
}
返回输出;
}


I've come up with

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

But I'm not sure how will v8 behave with that, for instance, will it really delete the other keys or will it only delete references and the garbage collector will bite me later ?

Also, I created these tests, I'm hoping you could add your answer there so we could see how they match up.

EDIT 1: Apparently, according to the tests, it's faster if we don't check if the key is already in lower case, but being faster aside, will it create more clutter by ignoring this and just creating new lower case keys ? Will the garbage collector be happy with this ?

解决方案

The fastest I come up with is if you create a new object:

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

I'm not familiar enough with the current inner working of v8 to give you a definitive answer. A few years ago I saw a video where the developers talked about objects, and IIRC it will only delete the references and let the garbage collector take care of it. But it was years ago so even if it was like that then, it doesn't need to be like that now.

Will it bite you later? It depends on what you are doing, but probably not. It is very common to create short lived objects so the code is optimized to handle it. But every environment has its limitations, and maybe it will bite you. You have to test with actual data.

Update 2017:

Added a utility function that can make a shallow or deep copy of an object, supporting circular references. Only briefly tested on node.

/** @summary objectKeysToLowerCase( input, deep, filter )
  * returns a new object with all own keys converted to lower case.
  * The copy can be shallow (default) or deep.
  *
  * Circular references is supported during deep copy and the output will have
  * the same structure.
  *
  * By default only objects that have Object as constructor is copied.
  * It can be changed with the "filter"-function.
  *
  * NOTE: If an object has multiple keys that only differs in case,
  * only the value of the last seen key is saved. The order is usually
  * in the order that the keys where created.
  * Exaple : input =  {aa:1, aA:2, Aa:3, AA:4}, output = {aa:4};
  *
  * NOTE: To detect circular references, the list of objects already converted
  * is searched for every new object. If you have too many objects, it will
  * be slower and slower...
  *
  * @param {object} input
  *   The source object
  * @param {boolean|number} deep
  *   A shallow copy is made if "deep" is undefined, null, false or 0.
  *   A deep copy is made if "deep" is true or a positive number.
  *   The number specifies how many levels to copy. Infinity is a valid number.
  *   This variable is used internally during deep copy.
  * @param {function} filter
  *   A filter function(object) to filter objects that should be copied.
  *   If it returns true, the copy is performed.
  * @returns {object}
  *
  */
function objectKeysToLowerCase( input, deep, filter ) {
  var idx, key, keys, last,  output, self, type, value;
  self = objectKeysToLowerCase;
  type = typeof deep;

  // Convert "deep" to a number between 0 to Infinity or keep special object.
  if ( type === 'undefined' || deep === null || deep === 0 || deep === false ) {
    deep = 0; // Shallow copy
  }
  else if ( type === 'object' ) {
    if ( !( deep instanceof self ) ) {
      throw new TypeError( 'Expected "deep" to be a special object' );
    }
  }
  else if ( deep === true ) {
    deep = Infinity; // Deep copy
  }
  else if ( type === 'number' ) {
    if ( isNaN(deep) || deep < 0 ) {
      throw new RangeError(
        'Expected "deep" to be a positive number, got ' + deep
      );
    }
  }
  else throw new TypeError(
    'Expected "deep" to be a boolean, number or object, got "' + type + '"'
  );


  // Check type of input, and throw if null or not an object.
  if ( input === null || typeof input !== 'object' ) {
    throw new TypeError( 'Expected "input" to be an object' );
  }

  // Check type of filter
  type = typeof filter;
  if ( filter === null || type === 'undefined' || type === 'function' ) {
    filter = filter || null;
  } else {
    throw new TypeError( 'Expected "filter" to be a function' );
  }

  keys = Object.keys(input); // Get own keys from object
  last = keys.length - 1;
  output = {}; // new object

  if (deep) { // only run the deep copy if needed.
    if (typeof deep === 'number') {
      // Create special object to be used during deep copy
      deep =
        Object.seal(
          Object.create(
            self.prototype,
            {
              input   : { value : [] },
              output  : { value : [] },
              level   : { value : -1, writable:true },
              max     : { value : deep, writable:false }
            }
          )
        );
    } else {
      // Circle detection
      idx = deep.input.indexOf( input );
      if ( ~idx ) {
        return deep.output[ idx ];
      }
    }

    deep.level += 1;
    deep.input.push( input );
    deep.output.push( output );

    idx = last + 1;
    while ( idx-- ) {
      key = keys[ last - idx ]; // Using [last - idx] to preserve order.
      value = input[ key ];
      if ( typeof value === 'object' && value && deep.level < deep.max ) {
        if ( filter ? filter(value) : value.constructor === Object ) {
          value = self( value, deep, filter );
        }
      }
      output[ key.toLowerCase() ] = value;
    }
    deep.level -= 1;
  } else {
    // Simple shallow copy
    idx = last + 1;
    while ( idx-- ) {
      key = keys[ last - idx ]; // Using [last - idx] to preserve order.
      output[ key.toLowerCase() ] = input[ key ];
    }
  }
  return output;
}

这篇关于将对象的所有按键都变为小写的最佳方式(最有效)是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆