I have implemented a recursive function that converts an objects keys according to another lookup table/map. You are able to convert back and forth using the 3rd `swap_conversion_table_key_value` boolean argument.

My use case is to convert object keys to single characters to slim down the amount of characters generated from `JSON.stringify`. Then be able to convert it back to full keys on another client.

Along with the usual code review criteria(mainly clarity), I am wondering if I just reinvented the wheel or overthought the whole problem. The code does seem a bit long for the functionality and I am not keen how how it directly modifies the object(wish it would return a new object). This means that you have to clone the data before every use to keep all the references to the original data happy.

# [Demo: jsFiddle](http://jsfiddle.net/MadLittleMods/g3g0g1L4/)

![](https://i.sstatic.net/QjRpw.png)

Usage:

    recursiveConvertKeys(resultant_data, conversion_table, false);

    // 3rd parameter defines whether we should swap the key-value in the table/map (good for converting back to the original data)
    recursiveConvertKeys(resultant_data, conversion_table, true);

## Code:
### Code available as a [GitHub Gist](https://gist.github.com/MadLittleMods/7b9ec36879fd24938ad2)

    function recursiveConvertKeys(data_object, conversion_table, swap_conversion_table_key_value, __is_recursive_iteration, __current_object_level, __current_conversion_table_level)
    {
    	// Do not pass in parameters for the double underscore arguments. These are private and only used for self recursive calling
    	//
    	// Demo: http://jsfiddle.net/MadLittleMods/g3g0g1L4/
    	// GitHub Gist: https://gist.github.com/MadLittleMods/7b9ec36879fd24938ad2
    	// Code Review: http://codereview.stackexchange.com/q/69651/40165
    	//
    	/* Usage: 
    		var data = {asdf: 1, qwer: 2};
    		var conversion_table = {asdf: 'a', qwer: 'q'};
     
    		// Clone the data so we don't overwrite it
    		var resultant_data = $.extend(true, {}, data);
    		// Now execute the key converting process
    		recursiveConvertKeys(resultant_data, conversion_table, false);
    		console.log("Reversed Data:", resultant_data);
    		
    		// If you want to reverse the process simply pass true for the `swap_conversion_table_key_value` argument
    		recursiveConvertKeys(resultant_data, conversion_table, true);
    		console.log("Back to normal Data:", resultant_data);
    	*/
    
    
    	// Start at the root of the objects when we invoke this method
    	__current_object_level = __is_recursive_iteration ? __current_object_level : data_object;
    	__current_conversion_table_level = __is_recursive_iteration ? __current_conversion_table_level : conversion_table;
    
    	
    	if(typeof __current_object_level == "object")
    	{
    		// Make the iterate object
    		var iterate_object = Object.keys(__current_object_level);
    		//console.log('iter', iterate_object);
    
    		iterate_object.map(function(key, index, array) {
    			// Check to make sure this is part of the object itself
    			if (__current_object_level.hasOwnProperty(key))
    			{
    				if(__current_conversion_table_level)
    				{
    					var new_key = null;
    					if(!swap_conversion_table_key_value)
    					{
    						if(typeof __current_conversion_table_level[key] == "object")
    							new_key = __current_conversion_table_level[key]['_short'];
    						else
    							new_key = __current_conversion_table_level[key];
    					}
    					else
    					{
    						// We have to search through all of the current level to match the value to curernt object key since we swapped
    						var table_level_keys = Object.keys(__current_conversion_table_level);
    						for(var i = 0; i < table_level_keys.length; i++)
    						{
    							var curr_level_table_key = table_level_keys[i];
    
    							var key_to_compare = null;
    							var curr_level_table_value = __current_conversion_table_level[curr_level_table_key];
    							if(typeof curr_level_table_value == "object")
    								key_to_compare = curr_level_table_value['_short'];
    							else
    								key_to_compare = curr_level_table_value;
    
    							// If it is a match, we found it :)
    							if(key_to_compare == key)
    							{
    								// Now use the key from the conversion table instead of the value
    								new_key = curr_level_table_key;
    
    								// Break out of the for loop after we found it
    								break;
    							}
    						}
    					}
    				
    					// If there is actually a new key, replace it in our object
    					if(new_key)
    					{
    						renameProperty(__current_object_level, key, new_key);
    					}
    
    					//console.log('key', key, new_key);
    
    					// Only keep going if there actually was a new_key
    					// Or there is a array to look through the items on
    					var is_current_key_array_index = key%1 == 0; // If the current key is a positive integer, we assume it is an array key
    					if(new_key || is_current_key_array_index)
    					{
    						// Use the new key if it was available
    						// Because that is what the object property is changed to from above
    						var value = __current_object_level[new_key ? new_key : key];
    
    						//console.log('current', value, __current_conversion_level);
    
    						// If we are swapping then the `key` will not be found in the table as it is ass-backwards.
    						var table_key = swap_conversion_table_key_value ? new_key : key;
    
    						// If the current key is a array, maintain the `_array_item` conversion level we set the level prior
    						// Otherwise continue down the tree
    						var next_conversion_level = is_current_key_array_index ? __current_conversion_table_level : __current_conversion_table_level[table_key];
    						if(typeof __current_conversion_table_level[table_key] == "object")
    						{
    							// If the current value is an array set up the conversion level for the items
    							if(Object.prototype.toString.call(value) === '[object Array]')
    							{
    								next_conversion_level = __current_conversion_table_level[table_key]['_array_item'];
    							}
    							else
    							{
    								next_conversion_level = __current_conversion_table_level[table_key]['_object'];
    							}
    						}
    						//console.log('next', next_conversion_level);
    						recursiveConvertKeys(data_object, conversion_table, swap_conversion_table_key_value, true, value, next_conversion_level);
    					}
    				}
    			}
    		});
    	}
    }

---

The format for the conversion table is below. I am not set on this format so feel free to suggest something better for the table/map.

    var conversion_table = {
    	"psdf": "p", 
    	"qwer": "q",
    	"dict": {
    		"_short": "d",
                
    		"_object": {
    			"one": "o",
    			"two": "t",
    			"three": "r"
    		}
    	},
    	"candidates": {
    		"_short": "c",
    
    		"_array_item": {
    			"ip": "i",
    			"port": "p"
    		}
    	}
    }

And some accompanying test data:

    var test_data = {
    	"psdf": "pcodereview",
    	"qwer": "qcodereview",
    	"dict": {
    		"one": "1",
    		"two": "2",
    		"three": "3"
    	},
    	"candidates": [
    		{
    			"ip": "0.0.0.0",
    			"port": 65000
    		},
    		{
    			"ip": "127.0.0.1",
    			"port": 65000
    		}
    	]
    }