Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Getting JavaScript Properties for Object Maps by Index or Name


Reflecting over JavaScript object properties, or more commonly object maps, is something that I always forget and have to look up over and over again, so I'm writing it down in hopes I can remember and have an easy place to look it up.

Iterating over a JavaScript Object

JavaScript has a rudimentary object iteration mechanism built into it so if you have an object and you want to get at all the properties and values of an object you can simply do:

var o = { "key1": "value1", "key2": "value2"};
for(var prop in o) {
  console.log(prop,o[prop]);  
}

That works but it requires iteration of the entire object which is not always what you want.

Getting a property by Name

As you can see above it's pretty easy to get a property by name:

var o = { "key1": "value1", "key2": "value2"};
var val = o["key2"];   // value2

Getting Object Properties by Index

What's not so straight forward is if you want to get both the value as well as the key - as a key value pair. This seems an odd request at first but it comes up frequently if you need to query or filter the data in any way using map, find or filter functions for example.

Quite frequently I want to be able to retrieve values for a specific key value pair where I may not know what the key name is, but only the index (most commonly the first item).

Enter the Object.keys() method which allows you to get a specific property name by index:

o = { "key1": "value1", "key2": "value2"};
var idx = 1; // key2

var key = Object.keys(o)[idx];
value = o[key]

console.log(key,value); // key2 value2

JavaScript Maps as Dictionaries

For me I run into this most commonly with object maps. Lots of applications including my own use object maps for holding lists of values or enumerated types. For example, in Markdown Monster I have a list of emoji's that are kept as a map with the markdown expansion (ie :smile:) as the key and the actual Emoji character as the value.

We often treat maps as dictionaries to hold look up values. But the interface to do this really sucks because a map is not really a good structure to filter or search because of the clunky object parsing interface you have to go through. However, I still use them because maps happen to serialize much nicer than an explicit object.

So this

emojis: { 
        ":100:" : "💯",
        ":1234:" : "🔢",
}    

is a bit cleaner than:

emojis: { 
        key: ":100:", value: "💯",
        key: ":1234:" value: "🔢"
}    

But the latter is easier to deal with if you use array.map/filter/find etc:

var match = "key2"
var val = o.find( function(item) { return item.key == match } );
console.log(val);

There's really no easy equivalent that you can use for a map that works the same.

A few simple Helpers

In order query a map a few helpers come in handy.

The following functions facilitate some of these tasks. Note you can also hang these off the Object prototype to make available natively on all objects, but I try to avoid that especially for low use case features like this so the functions below explicitly pass in the object to work on 😄.

For the following assume we have an object map:

var obj = { "key1": "value1", "key2": "value2", ":smile:":"😄"};

Getting a Value from a Map

As mentioned this doesn't really need any helpers. Just use:

var key = "key2";
var value = obj[key]  // value2
value = obj["bogus"]  // undefined

If the key doesn't exist you get back undefined. If you'd rather throw for this situation:

function getMapValue(obj, key) {
   if (obj.hasOwnProperty(key))
      return obj[key];
   throw new Error("Invalid map key."); 
}

With that you get:

var key = "key2";
var value = getMapValue(obj,key);      // value 2
var value = getMapValue(obj,"bogus");  // Error

Getting a Key and Value Object from a Map

As with the previous function if you need to get key value pairs transformed for a map or filter function you can just use this:

var key = "key1";
var kvpair = { key: key, value: obj[key] };  
// { key: "key1", value: "value1" }

key = "bogus"
var kvpair = { key: key, value: obj[key] };  
// { key: "bogus", value: undefined }

If you want a help that throws for invalid keys:

function getMapKeyValue(obj, key) {
   if (obj.hasOwnProperty(key))
      return { key: key, value: obj[key] };
   throw new Error("Invalid map key.");
}
var key = "key1";
var kvpair = getMapKeyValue(obj,key)
// { key: "key1", value: "value1" }

key = "bogus"
var kvpair = getMapKeyValue(obj,key); // Error

Get Key and Value by Index

The last scenario is an infrequent iteration one where you may need to get a property by its index. For example, you may have a filtered list where you know there's a fixed result and you just want to grab a specific result - typically the first one.

function getMapKeyValueByIndex(obj, idx) {
   var key = Object.keys(obj)[idx];
   return { key: key, value: obj[key] };
}

Not a common use case but I found this useful on a few occasions.

A few more examples in context

o = { "key1": "value1", "key2": "value2", ":smile:":"😄"};
var idx = 0; 

prop = Object.keys(o)[idx];    
value = o[prop]             
console.log(prop,value);   // key1, value1

console.log(getMapValue(o,":smile:"));   // 😄

console.log(getMapKeyValue(o,"key1"));  // { key: "key1", value: "value1" }

console.log(getMapKeyValueByIndex(o,2)); // { key: ":smile", value: "😄" }

Again - nothing really new here, but this is meant more as a note to self for myself 😄.

Resources

this post created with Markdown Monster

I'll be at DevIntersection in Vegas this fall giving sessions on ASP.NET Core with Angular and Localization. Thinking of coming? Use discount code STRAHL and save a few bucks. If you do be sure to stop by and say hello!

ASP.NET DevIntersection 2017. Rick Strahl Coupon Code

Posted in JavaScript  

The Voices of Reason


 

snerks
March 05, 2017

# re: Getting JavaScript Properties for Object Maps by Index or Name

If TypeScript is an option, the keyof feature may be useful for this kind of thing:

https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#typescript-21


wqw
March 06, 2017

# re: Getting JavaScript Properties for Object Maps by Index or Name

The iter var prop is not used in the body of these for loops. Am I missing something?


Rick Strahl
March 06, 2017

# re: Getting JavaScript Properties for Object Maps by Index or Name

@wqw - quite right. Pointed at old copies (sheesh). Updated code samples and CodePen is correct.

 

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2017