不区分大小写访问JavaScript属性?


78

假设我有一个对象:

var obj = {
  foo:"bar",
  fizz:"buzz"
};

我需要像这样动态地访问该对象的属性:

var objSetter = function(prop,val){
  obj[prop] = val;
}

那里没有任何问题,除了prop万一属性名称以Foo代替的形式传递给函数时,它不需要区分大小写foo

那么,如何不区分大小写地通过名称指向对象的属性呢?如果可能,我想避免迭代整个对象。


7
你不能 语言区分大小写。想想obj = {foo: true, Foo: false}
user123444555621 2012年

始终将您的实际属性名称全部保留为小写(或大写),然后在查询时进行转换。
Pointy 2012年

如果您期望使用“ foo”而不是“ Foo”,则可以prop在使用前将其转换为小写。
Claudio Redi 2012年

1
看看JavaScript代理对象来实现是为有效地改变一个通配符吸气的手段:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
扎克·史密斯

不要这样做。停止提供允许草率发展的机制。按键区分大小写。如果您允许其他人使用大小写不同的密钥,那么您将允许他们创建难以维护的糟糕代码,更不用说速度较慢了,因为您必须运行特殊代码以允许密钥在不应该使用时进行匹配。
Intervalia

Answers:


27

将obj的所有属性与prop进行比较。

var objSetter = function(prop,val){
  prop = (prop + "").toLowerCase();
  for(var p in obj){
     if(obj.hasOwnProperty(p) && prop == (p+ "").toLowerCase()){
           obj[p] = val;
           break;
      }
   }
}

2
谢谢。当然可以,但是我希望避免迭代整个对象。我将编辑我的帖子以使其更加清晰。再次感谢。
Matt Cashatt 2012年

感谢Shusl,看起来迭代是我唯一的选择。另外,您能告诉我这+ ""是做什么用的吗?这仅用于字符串转换吗?
Matt Cashatt 2012年

1
确保将toLowerCase应用于字符串。例如。(1 +“”)会将1转换为“ 1”。
Anoop 2012年

16
无需强制p使用字符串,ECMA-262将对象属性指定为字符串,任何不符合要求的用户代理或主机都会遇到严重问题。也没有必要break,应该使用return
RobG 2012年

2
我在具有超过一百万个键的对象上尝试了此操作,它的速度令人难以忍受。更好的方法是使用代理对象(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)。或者,如果您的用例允许的话,也可以在字典中以大写字母开头添加键
Zach Smith

40

试试这个:

var myObject = { "mIxeDCaSEKeY": "value" };

var searchKey = 'mixedCaseKey';
myObject[Object.keys(myObject).find(key => key.toLowerCase() === searchKey.toLowerCase())];

您也可以选择以小写形式提供searchKey。

如果您希望将其用作功能:

/**
  * @param {Object} object
  * @param {string} key
  * @return {any} value
 */
function getParameterCaseInsensitive(object, key) {
  return object[Object.keys(object)
    .find(k => k.toLowerCase() === key.toLowerCase())
  ];
}

如果找不到该对象,则它将返回undefined,就像正常情况一样。

如果需要支持较旧的浏览器,则可以filter改用:

function getParameterCaseInsensitive(object, key) {
  return object[Object.keys(object).filter(function(k) {
    return k.toLowerCase() === key.toLowerCase();
  })[0]];
}

如果您需要更早的支持,我建议对Object.keys()Array.filter()使用polyfills


我很好奇,什么是文档注释样式。然后我找到了jsdoc.app/about-getting-started.html
Michael Freidgeim

1
TypeScript还将本地读取JSDocs并执行类型检查。它内置于VSCode中,使生活更轻松。
保险丝

10

为此,我更喜欢使用原型而不是独立功能,只是为了易于使用和表达。我只是不喜欢将对象集中到函数中。

另外,虽然可接受的答案有效,但我希望获得和设置都更全面的解决方案,使其表现得尽可能像本机点表示法或方括号表示法。

考虑到这一点,我创建了几个原型函数,用于在不考虑大小写的情况下设置/获取对象属性。添加到对象原型时,您必须记住要非常负责。特别是在使用JQuery和其他库时。可枚举设置为false的Object.defineProperty()专门用于避免与JQuery冲突。我也没有在函数上命名任何不区分大小写的东西,但是您当然可以。我喜欢简称。

这是吸气剂:

Object.defineProperty(Object.prototype, "getProp", {
    value: function (prop) {
        var key,self = this;
        for (key in self) {
            if (key.toLowerCase() == prop.toLowerCase()) {
                return self[key];
            }
        }
    },
    //this keeps jquery happy
    enumerable: false
});

这是二传手:

Object.defineProperty(Object.prototype, "setProp", {
    value: function (prop, val) {
        var key,self = this;
        var found = false;
        if (Object.keys(self).length > 0) {
            for (key in self) {
                if (key.toLowerCase() == prop.toLowerCase()) {
                    //set existing property
                    found = true;                        
                    self[key] = val;
                    break;
                }
            }
        }

        if (!found) {
            //if the property was not found, create it
            self[prop] = val;
        }  

        return val;
    },
    //this keeps jquery happy
    enumerable: false
});

现在,我们已经创建了这些功能,我们的代码非常简洁明了,并且可以正常工作。

不区分大小写的获取:

var obj = {foo: 'bar', camelCase: 'humpy'}

obj.getProp("FOO");          //returns 'bar'
obj.getProp("fOO");          //returns 'bar'
obj.getProp("CAMELCASE");    //returns 'humpy' 
obj.getProp("CamelCase");    //returns 'humpy'

不区分大小写的设置:

var obj = {foo: 'bar', camelCase: 'humpy'}

obj.setProp('CAmelCasE', 'super humpy');     //sets prop 'camelCase' to 'super humpy'
obj.setProp('newProp', 'newval');      //creates prop 'newProp' and sets val to 'newval'  
obj.setProp('NewProp', 'anotherval');  //sets prop 'newProp' to 'anotherval'

1
当然,一旦有人这样做,这将可怕地失败obj.setProp("GETPROP")
Bergi

6

对已经介绍的内容的另一种变化形式将迭代推入Underscore / LodashfindKey函数:

var _ = require('underscore');
var getProp = function (obj, name) {
    var realName = _.findKey(obj, function (value, key) {
        return key.toLowerCase() === name.toLowerCase();
    });
    return obj[realName];
};

例如:

var obj = { aa: 1, bB: 2, Cc: 3, DD: 4 };
getProp(obj, 'aa'); // 1
getProp(obj, 'AA'); // 1
getProp(obj, 'bb'); // 2
getProp(obj, 'BB'); // 2
getProp(obj, 'cc'); // 3
getProp(obj, 'CC'); // 3
getProp(obj, 'dd'); // 4
getProp(obj, 'DD'); // 4
getProp(obj, 'EE'); // undefined

underscore图书馆如何实现呢?即,我正在寻找一种不涉及某些对象键的线性搜索的方法
Zach Smith,

2
@ZachSmith是O(n); 看这里
Rusty Shackleford

3

您可以执行此操作以“规范化” prop

 var normalizedProp = prop.toLowerCase();
 obj[normalizedProp] = val;

1
谢谢。我知道如何将其强制转换prop为小写字母,但是如果我不能保证实际的属性名称全部为小写字母怎么办?也许我缺少什么?
Matt Cashatt 2012年

1
@MatthewPatrickCashatt您什么都不会错过:没什么可错过的-因为这里没有什么语言可以帮助您:)

3
否决投票的原因:就像@RobG的答案一样,该属性无法回答所假定的问题,因为该属性为小写字母。
马特·古德温

1

不需要任何迭代。由于prop可能不是字符串,因此应先将其强制转换为字符串,因为这是对象的本机操作。一个简单的getter函数是:

function objGetter(prop) {
  return obj[String(prop).toLowerCase()];
}

如果需要重新串接对自己的属性的访问:

function objGetter(prop) {
  prop = String(prop).toLowerCase();

  if (obj.hasOwnProperty(prop)) {
    return obj.prop;
  }
}

和二传手:

function objSetter(prop, val) {
  obj[String(prop).toLowerCase()] = val;
}

2
假定源对象上的所有属性均为小写。
克里斯·海恩斯

同意@Hainesy,这是假定情况,这与问题的实质相反。
马特·古德温

@MattGoodwin-您似乎错过了setter,该setter以小写名称创建属性。
RobG

@RobG我对这个答案的问题是,给定一个对象的属性名称带有大小写不确定的情况,除非该属性本身最初是使用您的方法创建的,或者该属性恰好是小写的,否则您的解决方案将不会检索该值。我相信发问者所要求的是一种在未知属性的情况下可以访问对象属性的方法。
马特·古德温

@MattGoodwin,重新阅读作者的问题。他并不表示他无法控制该对象。问题是关于prop传递给objSetter()函数的情况。实际上,质疑者首先将objSetter()函数包含进来就强烈暗示了作者可以控制对象的创建。指出属性名称必须规范化为小写并提供帮助的答案是一个合理的答案。如果作者还有其他需求,则可以在评论中或通过编辑问题进行澄清。
bobpaul

1

当我们简单地将它们全部转换成小写时,为什么我们会做那么复杂:

    var your_object = { 
"chickago" : 'hi' ,
 "detroit" : 'word', 
 "atlanta" : 'get r dun',     
GetName: function (status) {
        return this[status].name;
    } };

称呼它: your_object.GetName(your_var.toLowerCase());


5
假设您已控制了对象的创建,并且对象中的键是小写字母
velop '18

1

在我看来,代理服务器是一个不错的选择,可以使用陷阱将字符串键转换为大写或小写,并且表现得像普通对象。这适用于两种符号:点或球拍

这是代码:

'use strict';

function noCasePropObj(obj)
{
	var handler =
	{
		get: function(target, key)
			{
				//console.log("key: " + key.toString());
				if (typeof key == "string")
				{
					var uKey = key.toUpperCase();

					if ((key != uKey) && (key in target))
						return target[key];
					return target[uKey];
				}
				return target[key];
			},
		set: function(target, key, value)
			{
				if (typeof key == "string")
				{
					var uKey = key.toUpperCase();

					if ((key != uKey) && (key in target))
						target[key] = value;
					target[uKey] = value;
				}
				else
					target[key] = value;
			},
		deleteProperty: function(target, key)
			{
				if (typeof key == "string")
				{
					var uKey = key.toUpperCase();

					if ((key != uKey) && (key in target))
						delete target[key];
					if (uKey in target)
						delete target[uKey];
				}
				else
					delete target[key];
			},
	};
	function checkAtomic(value)
	{
		if (typeof value == "object")
			return new noCasePropObj(value); // recursive call only for Objects
		return value;
	}

	var newObj;

	if (typeof obj == "object")
	{
		newObj = new Proxy({}, handler);
        // traverse the Original object converting string keys to upper case
		for (var key in obj)
		{
			if (typeof key == "string")
			{
				var objKey = key.toUpperCase();

				if (!(key in newObj))
					newObj[objKey] = checkAtomic(obj[key]);
			}
		}
	}
	else if (Array.isArray(obj))
	{
        // in an array of objects convert to upper case string keys within each row
		newObj = new Array();
		for (var i = 0; i < obj.length; i++)
			newObj[i] = checkAtomic(obj[i]);
	}
	return newObj; // object with upper cased keys
}

// Use Sample:
var b = {Name: "Enrique", last: "Alamo", AdDrEsS: {Street: "1233 Main Street", CITY: "Somewhere", zip: 33333}};
console.log("Original: " + JSON.stringify(b));  // Original: {"Name":"Enrique","last":"Alamo","AdDrEsS":{"Street":"1233 Main Street","CITY":"Somewhere","zip":33333}}
var t = noCasePropObj(b);
console.log(JSON.stringify(t)); // {"NAME":"Enrique","LAST":"Alamo","ADDRESS":{"STREET":"1233 Main Street","CITY":"Somewhere","ZIP":33333}}
console.log('.NaMe:' + t.NaMe); // .NaMe:Enrique
console.log('["naME"]:' + t["naME"]); // ["naME"]:Enrique
console.log('.ADDreSS["CitY"]:' + t.ADDreSS["CitY"]); // .ADDreSS["CitY"]:Somewhere
console.log('check:' + JSON.stringify(Object.getOwnPropertyNames(t))); // check:["NAME","LAST","ADDRESS"]
console.log('check2:' + JSON.stringify(Object.getOwnPropertyNames(t['AddresS']))); // check2:["STREET","CITY","ZIP"]


1
const getPropertyNoCase = (obj, prop) => obj[Object.keys(obj).find(key => key.toLowerCase() === prop.toLowerCase() )];

要么

const getPropertyNoCase = (obj, prop) => {
    const lowerProp = prop.toLowerCase(obj[Object.keys(obj).find(key => key.toLowerCase() === prop.toLowerCase() )];
}

0

这是执行此操作的非常简单的代码,假设数据是对象数组,例如

data=[{"A":"bc","B":"nn"}]

var data=data.reduce(function(prev, curr) {
    var cc = curr; // current value
    var K = Object.keys(cc); // get all keys
    var n = {};
    for (var i = 0; i < K.length; i++) {
        var key = K[i];//get hte key

        n[key.toLowerCase()] = cc[key] // convert to lowercase and assign 
    }
    prev.push(n) // push to array
    return prev;
}, [])

输出将是

data=[{"a":"bc","b":"nn"}]

0

如果区分大小写的匹配(便宜又快速)失败了,您可能只需要进行不区分大小写的匹配(由于对象迭代而通常比较昂贵)。

说您有:

var your_object = { "Chicago" : 'hi' , "deTroiT" : 'word' , "atlanta" : 'get r dun' } ;

无论出于何种原因,您都有the_value ,Detroit

if( your_object.hasOwnProperty( the_value ) ) 
  { 
    // do what you need to do here
  } 
else  
  { // since the case-sensitive match did not succeed, 
    //   ... Now try a the more-expensive case-insensitive matching

    for( let lvs_prop in your_object ) 
      { if( the_value.toLowerCase()  == lvs_prop.toLowerCase() ) 
          { 

            // do what you need to do here

            break ;
          } ;
      } 
  } ;

0

另一个简单的方法:

function getVal(obj, prop){
var val;
  prop = (prop + "").toLowerCase();
  for(var p in obj){
     if(obj.hasOwnProperty(p) && prop == (p+ "").toLowerCase()){
           val = obj[p]
           break;
      }
   }
   return val;
}

像这样使用它:

var obj = {
  foo:"bar",
  fizz:"buzz"
};
    getVal(obj,"FoO") -> returns "bar"

0

该答案需要ES6。

const x = {'X-Total-Count':10};
console.log(x[Object.keys(x).reduce(key=>{return key.match(/x-total-count/i)})]);


0

这是一个很好的递归函数,它允许您以不区分大小写的方式遍历javascript对象:

let testObject = {'a': {'B': {'cC': [1,2,3]}}}
let testSeq = ['a','b','cc']

function keySequence(o, kseq) {
  if(kseq.length==0){ return o; }
  let validKeys = Object.keys(o).filter(k=>k.toLowerCase()==kseq[0].toLowerCase());
  if(validKeys.length==0) { return `Incorrect Key: ${kseq[0]}` }
  return keySequence(o[validKeys[0]], kseq.slice(1))
}

keySequence(testObject, testSeq); //returns [1,2,3]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.