Access JavaScript property case-insensitively?

JavascriptObjectProperties

Javascript Problem Overview


Assume I have an object:

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

I need to access a property of that object dynamically like so:

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

No problems there, except for that prop needs to be case insensitive in case the property name is passed into the function as, say, Foo instead of foo.

So how can I point to an object's property by name without regard to case? I would like to avoid iterating the entire object if possible.

Javascript Solutions


Solution 1 - Javascript

Try this:

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

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

You can alternatively already provide the searchKey in lowercase.

If you want it as a function:

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

If the key can't be found, then it'll return undefined, just like normal.

If you need to support older browsers, then you can use filter instead:

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

I suggest using the polyfills for Object.keys() and Array.filter() if you need even older support.


Note: If you want to also check non-enumerable keys, use Object.getOwnPropertyNames() instead of Object.keys().

Nerdy Note: This assumes your Object doesn't have a key undefined (eg: const foo = {[undefined]: 'bar'};). That's just weird.

Solution 2 - Javascript

Compare all the properties of obj with 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;
      }
   }
}

Solution 3 - Javascript

For this, I prefer using the prototype over a standalone function just for ease of use and expressiveness. I just don't like funneling objects into functions if I don't have to.

Also, while the accepted answer works, I wanted a more comprehensive solution for both getting and setting that would behave as much like the native dot notation or bracket notation as possible.

With that in mind, I created a couple prototype functions for setting/getting an object property without regard to case. You have to remember to be VERY responsible when adding to the Object prototype. Especially when using JQuery and other libraries. Object.defineProperty() with enumerable set to false was used specifically to avoid conflict with JQuery. I also didn't bother naming the functions anything that indicates they are case-insensitive, but you certainly could. I like shorter names.

Here's the getter:

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

Here's the setter:

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

Now that we've created those functions, our code is super clean and concise and just works.

Case-insensitive getting:

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'

Case-insensitive setting:

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'

Solution 4 - Javascript

Yet another variation on those already presented which pushes the iteration down into the Underscore/Lodash findKey function:

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

For example:

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

Solution 5 - Javascript

You could do this in order to "normalize" prop

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

Solution 6 - Javascript

It seems to me like a good candidate for Proxy with traps to convert string keys to either upper case or lower case and behaving like a regular object. This works with either notation: dots or braquets

Here is the code:

'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"]

Solution 7 - Javascript

This answer requires ES6.

const x = { 'aB': 1, 'X-Total-Count': 10, y3: 2 } console.log(x[Object.keys(x).find(key=>{return key.match(/^ab$/i)})]) console.log(x[Object.keys(x).find(key=>{return key.match(/^x-total-count$/i)})]) console.log(x[Object.keys(x).find(key=>{return key.match(/^y3$/i)})])

Solution 8 - Javascript

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

or

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

Solution 9 - Javascript

The ES6 example posted by @nilloc is incorrect and will break in use.

Here is a working example:

const x = {'first':5,'X-Total-Count':10,'third':20};
console.log(x[Object.keys(x).reduce((result,key)=>{
   if (!result) {
      return key.match(/x-total-count/i)
   } else {
      return result;
   }
 },null)]);

or better yet, it should return undefined if the key doesn't exist:

const x = {'first':5,'X-Total-Count':10,'third':20};
console.log(x[Object.keys(x).reduce((result,key)=>{
   if (!result) {
     return key.match(/x-total-count/i) || undefined
   } else {
     return result;
   }
  },undefined)]);

One consideration is that the above example will return the last matching key in the object if there are multiple keys that match.

Here is an example with the code made into a function:

/**
  * @param {Object} object
  * @param {string} key
  * @return {string||undefined} value || undefined
 */
function getKeyCase(obj,key) {
  const re = new RegExp(key,"i");
  return Object.keys(obj).reduce((result,key)=>{
   if (!result) {
     return key.match(re) || undefined
   } else {
     return result;
   }
  },undefined);

const x = {'first':5,'X-Total-Count':10,'third':20};

console.log(x[getKeyCase(x,"x-total-count")]);

Solution 10 - Javascript

Its really sad that the iteration can't be skipped as it seems. For me what is acceptable but may not be for everyone is to shape the object one time via iteration and then use it in regular hashmap fashion.

const hashmap = {
  'FOO': 'foo as in function programming',
  'bar': 'bar is in baz',
};

const shapedmap = Object.entries(hashmap).reduce(
  (acc, [key, val]) => (acc[key.toUpperCase()] = val, acc), {}
);

for (const term of ['foo', 'bar', 'baz']) {
  const match = shapedmap[term.toUpperCase()]
  match && console.log('awesome, we got the term.', match);
};

Even if it just one time lookup has to be performed, it shouldn't less performant as any other iteration solution since after 1 pass, the lookup speed is constant. (I guess).

Solution 11 - Javascript

There is no need for any iteration. Since prop might not be a string, it should be coerced to a string first where appropriate since that's what objects do natively. A simple getter function is:

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

If there is a requirement is to restring access to own properties:

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

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

and a setter:

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

Solution 12 - Javascript

Heres a very simple code to do this Assuming that data is the array of objects like

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

Output will be

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

Solution 13 - Javascript

You might only need to do case-insensitive matching (usually expensive because of object iteration) IF a case-sensitive match (cheap and quick) fails.

Say you have:

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

And you have, for whatever reason, 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 ;
		  } ;
	  } 
  } ;

Solution 14 - Javascript

why would we do it that complicated when we simply can make it all lower case:

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

to call it: your_object.GetName(your_var.toLowerCase());

Solution 15 - Javascript

Another simple way:

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

Use it like this:

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

Solution 16 - Javascript

Here is a nice recursive function that allows you to traverse a javascript object in a case-insensitive way:

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]

Solution 17 - Javascript

This will convert everything to lowercase, but in a bind this could help if you are not concerned with retaining case.

var somedata = {
    "MixEdCase": 1234
}

var temp = JSON.parse(JSON.stringify(somedata).toLowerCase());

console.log(temp.mixedcase);
// or
console.log(temp["mixedcase"]);

Solution 18 - Javascript

This is an old question, but it was the first one I found. As @ZachSmith says, you can use a Proxy. Here's some example code:

function lowercase(oldKey) {
    // Check that it's a string.
    return typeof oldKey === 'string' ? oldKey.toLowerCase() : oldKey;
}
const propertiesMap = new Map(
    Object.keys(obj).map(propKey => [lowercase(propKey), obj[propKey]])
);
const caseInsensitiveGetHandler = {
    get: function(target, property, receiver) {
        return propertiesMap.get(lowercase(property));
    }
};
obj = new Proxy(obj, caseInsensitiveGetHandler);

For my use case, I only needed to proxy the object's getter, but you may need to implement more of the Proxy methods.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatt CashattView Question on Stackoverflow
Solution 1 - JavascriptShortFuseView Answer on Stackoverflow
Solution 2 - JavascriptAnoopView Answer on Stackoverflow
Solution 3 - JavascriptMatthew GoodwinView Answer on Stackoverflow
Solution 4 - JavascriptRusty ShacklefordView Answer on Stackoverflow
Solution 5 - JavascriptClaudio RediView Answer on Stackoverflow
Solution 6 - JavascriptEnrique AlamoView Answer on Stackoverflow
Solution 7 - JavascriptCollin ThomasView Answer on Stackoverflow
Solution 8 - JavascriptYaron PdutView Answer on Stackoverflow
Solution 9 - JavascriptDan WillettView Answer on Stackoverflow
Solution 10 - JavascriptThe FoolView Answer on Stackoverflow
Solution 11 - JavascriptRobGView Answer on Stackoverflow
Solution 12 - JavascriptprajnavanthaView Answer on Stackoverflow
Solution 13 - JavascriptdsdsdsdsdView Answer on Stackoverflow
Solution 14 - JavascriptKaiOsmonView Answer on Stackoverflow
Solution 15 - JavascriptGorvGoylView Answer on Stackoverflow
Solution 16 - JavascriptcbartondockView Answer on Stackoverflow
Solution 17 - JavascriptRouan van der EndeView Answer on Stackoverflow
Solution 18 - Javascriptwhistling_marmotView Answer on Stackoverflow