Skip to main content
Code Review

Return to Answer

deleted 32 characters in body
Source Link
konijn
  • 34.2k
  • 5
  • 70
  • 267
// from: http://stackoverflow.com/a/4648411/796832
// Check for the old property name to avoid a ReferenceError in strict mode.
function renameProperty(object, oldName, newName) {
 if (object.hasOwnProperty(oldName)) {
 object[newName] = object[oldName];
 delete object[oldName];
 return object[newName];
 }
}
function convertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).map(function(key) {
 var mappedKey = map[key];
 if (!mappedKey) {
 return;
 }
 var value = object[key];
 if (mappedKey instanceof Object) {
 if (mappedKey._short) {
 value = renameProperty(object, key, mappedKey._short);
 }
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 convertKeys(value[i], mappedKey._array_item);
 }
 } else if (value instanceof Object) {
 convertKeys(value, mappedKey._object);
 }
 } else {
 renameProperty(object, key, mappedKey);
 }
 });
}
function findValueKey(object, searchValue) {
 var keys = Object.keys(object), key, value;
 
 for (var i = 0, length = keys.length; i < length; i++) {
 key = keys[i];
 value = object[key]; 
 if (value === searchValue) {
 return key;
 }
 if( value instanceof Object && value._short == searchValue ){
 return key;
 }
 }
}
function revertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).forEach(function(key) {
 var mappedKey = findValueKey(map, key);
 if (!mappedKey) {
 return;
 }
 var value = renameProperty(object, key, mappedKey),
 subMap = map[mappedKey];
 console.log( subMap );
 if (subMap instanceof Object) {
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 revertKeys(value[i], subMap._array_item);
 }
 } else if (value instanceof Object) {
 revertKeys(value, subMap._object);
 }
 }
 });
}
$('textarea').tabOverride();
$('.go').on('click', function() {
 // Tests
 // ---------------------------
 var data = JSON.parse($('.data-box').val());
 var conversion_table = JSON.parse($('.conversion-table-box').val());
 // Clone the data so we don't overwrite it
 var resultant_data = $.extend(true, {}, data);
 // Now execute the key converting process
 convertKeys(resultant_data, conversion_table);
 $('.result').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Reversed Data:", resultant_data);
 // If you want to reverse the process simply pass true for the `swap_conversion_table_key_value` argument
 revertKeys(resultant_data, conversion_table);
 $('.result-back-to-normal').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Back to normal Data:", resultant_data);
}).trigger('click');
*, *:before, *:after {
 -moz-box-sizing: border-box;
 -webkit-box-sizing: border-box;
 box-sizing: border-box;
}
html, body
{
 width: 100%;
 height: 100%;
 margin: 0;
 padding: 0;
 
 font-family: Arial, sans-serif;
}
pre, textarea 
{
 tab-size: 4;
 -moz-tab-size: 4;
 -o-tab-size: 4;
 -webkit-tab-size: 4;
}
textarea, pre
{
 width: 100%;
 min-height: 150px;
 
 padding: 4px;
}
.side-by-side-section
{
 display: flex;
}
.side-by-side-section > *
{
 flex: 1;
}
.code-block
{
 background: rgba(0, 0, 0, 0.1);
 border: 1px solid rgba(0, 0, 0, 0.2);
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Map keys" />
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//rawgit.com/wjbryant/taboverride/master/build/output/taboverride.js"></script>
<script src="//rawgit.com/wjbryant/jquery.taboverride/master/src/jquery.taboverride.js"></script>
 <meta charset="utf-8">
 <title>JS Bin</title>
</head>
<body>
<button class="go">Go</button>
Write data and conversion table in JSON.
<br />
<div class="side-by-side-section">
 <div>
 <div>Data:</div>
 <textarea class="data-box">
{
 "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
 }
 ]
} 
 </textarea>
 </div>
 <div>
 <div>Conversion table:</div>
 <textarea class="conversion-table-box">
{
 "psdf": "p", 
 "qwer": "q",
 "dict": {
 "_short": "d",
 
 "_object": {
 "one": "o",
 "two": "t",
 "three": "r"
 }
 },
 "candidates": {
 "_short": "c",
 "_array_item": {
 "ip": "i",
 "port": "p"
 }
 }
}
 </textarea>
 </div>
</div>
<div class="side-by-side-section">
 <div>
 <div>Converted:</div>
 <pre class="code-block"><code class="result"></code></pre>
 </div>
 <div>
 <div>Converted back:</div>
 <pre class="code-block"><code class="result-back-to-normal"></code></pre>
 </div>
</div>
</body>
</html>
// from: http://stackoverflow.com/a/4648411/796832
// Check for the old property name to avoid a ReferenceError in strict mode.
function renameProperty(object, oldName, newName) {
 if (object.hasOwnProperty(oldName)) {
 object[newName] = object[oldName];
 delete object[oldName];
 return object[newName];
 }
}
function convertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).map(function(key) {
 var mappedKey = map[key];
 if (!mappedKey) {
 return;
 }
 var value = object[key];
 if (mappedKey instanceof Object) {
 if (mappedKey._short) {
 value = renameProperty(object, key, mappedKey._short);
 }
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 convertKeys(value[i], mappedKey._array_item);
 }
 } else if (value instanceof Object) {
 convertKeys(value, mappedKey._object);
 }
 } else {
 renameProperty(object, key, mappedKey);
 }
 });
}
function findValueKey(object, searchValue) {
 var keys = Object.keys(object), key, value;
 
 for (var i = 0, length = keys.length; i < length; i++) {
 key = keys[i];
 value = object[key]; 
 if (value === searchValue) {
 return key;
 }
 if( value instanceof Object && value._short == searchValue ){
 return key;
 }
 }
}
function revertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).forEach(function(key) {
 var mappedKey = findValueKey(map, key);
 if (!mappedKey) {
 return;
 }
 var value = renameProperty(object, key, mappedKey),
 subMap = map[mappedKey];
 console.log( subMap );
 if (subMap instanceof Object) {
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 revertKeys(value[i], subMap._array_item);
 }
 } else if (value instanceof Object) {
 revertKeys(value, subMap._object);
 }
 }
 });
}
$('textarea').tabOverride();
$('.go').on('click', function() {
 // Tests
 // ---------------------------
 var data = JSON.parse($('.data-box').val());
 var conversion_table = JSON.parse($('.conversion-table-box').val());
 // Clone the data so we don't overwrite it
 var resultant_data = $.extend(true, {}, data);
 // Now execute the key converting process
 convertKeys(resultant_data, conversion_table);
 $('.result').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Reversed Data:", resultant_data);
 // If you want to reverse the process simply pass true for the `swap_conversion_table_key_value` argument
 revertKeys(resultant_data, conversion_table);
 $('.result-back-to-normal').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Back to normal Data:", resultant_data);
}).trigger('click');
*, *:before, *:after {
 -moz-box-sizing: border-box;
 -webkit-box-sizing: border-box;
 box-sizing: border-box;
}
html, body
{
 width: 100%;
 height: 100%;
 margin: 0;
 padding: 0;
 
 font-family: Arial, sans-serif;
}
pre, textarea 
{
 tab-size: 4;
 -moz-tab-size: 4;
 -o-tab-size: 4;
 -webkit-tab-size: 4;
}
textarea, pre
{
 width: 100%;
 min-height: 150px;
 
 padding: 4px;
}
.side-by-side-section
{
 display: flex;
}
.side-by-side-section > *
{
 flex: 1;
}
.code-block
{
 background: rgba(0, 0, 0, 0.1);
 border: 1px solid rgba(0, 0, 0, 0.2);
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Map keys" />
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//rawgit.com/wjbryant/taboverride/master/build/output/taboverride.js"></script>
<script src="//rawgit.com/wjbryant/jquery.taboverride/master/src/jquery.taboverride.js"></script>
 <meta charset="utf-8">
 <title>JS Bin</title>
</head>
<body>
<button class="go">Go</button>
Write data and conversion table in JSON.
<br />
<div class="side-by-side-section">
 <div>
 <div>Data:</div>
 <textarea class="data-box">
{
 "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
 }
 ]
} 
 </textarea>
 </div>
 <div>
 <div>Conversion table:</div>
 <textarea class="conversion-table-box">
{
 "psdf": "p", 
 "qwer": "q",
 "dict": {
 "_short": "d",
 
 "_object": {
 "one": "o",
 "two": "t",
 "three": "r"
 }
 },
 "candidates": {
 "_short": "c",
 "_array_item": {
 "ip": "i",
 "port": "p"
 }
 }
}
 </textarea>
 </div>
</div>
<div class="side-by-side-section">
 <div>
 <div>Converted:</div>
 <pre class="code-block"><code class="result"></code></pre>
 </div>
 <div>
 <div>Converted back:</div>
 <pre class="code-block"><code class="result-back-to-normal"></code></pre>
 </div>
</div>
</body>
</html>
// from: http://stackoverflow.com/a/4648411/796832
// Check for the old property name to avoid a ReferenceError in strict mode.
function renameProperty(object, oldName, newName) {
 if (object.hasOwnProperty(oldName)) {
 object[newName] = object[oldName];
 delete object[oldName];
 return object[newName];
 }
}
function convertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).map(function(key) {
 var mappedKey = map[key];
 if (!mappedKey) {
 return;
 }
 var value = object[key];
 if (mappedKey instanceof Object) {
 if (mappedKey._short) {
 value = renameProperty(object, key, mappedKey._short);
 }
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 convertKeys(value[i], mappedKey._array_item);
 }
 } else if (value instanceof Object) {
 convertKeys(value, mappedKey._object);
 }
 } else {
 renameProperty(object, key, mappedKey);
 }
 });
}
function findValueKey(object, searchValue) {
 var keys = Object.keys(object), key, value;
 
 for (var i = 0, length = keys.length; i < length; i++) {
 key = keys[i];
 value = object[key]; 
 if (value === searchValue) {
 return key;
 }
 if( value instanceof Object && value._short == searchValue ){
 return key;
 }
 }
}
function revertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).forEach(function(key) {
 var mappedKey = findValueKey(map, key);
 if (!mappedKey) {
 return;
 }
 var value = renameProperty(object, key, mappedKey),
 subMap = map[mappedKey];
 if (subMap instanceof Object) {
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 revertKeys(value[i], subMap._array_item);
 }
 } else if (value instanceof Object) {
 revertKeys(value, subMap._object);
 }
 }
 });
}
$('textarea').tabOverride();
$('.go').on('click', function() {
 // Tests
 // ---------------------------
 var data = JSON.parse($('.data-box').val());
 var conversion_table = JSON.parse($('.conversion-table-box').val());
 // Clone the data so we don't overwrite it
 var resultant_data = $.extend(true, {}, data);
 // Now execute the key converting process
 convertKeys(resultant_data, conversion_table);
 $('.result').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Reversed Data:", resultant_data);
 // If you want to reverse the process simply pass true for the `swap_conversion_table_key_value` argument
 revertKeys(resultant_data, conversion_table);
 $('.result-back-to-normal').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Back to normal Data:", resultant_data);
}).trigger('click');
*, *:before, *:after {
 -moz-box-sizing: border-box;
 -webkit-box-sizing: border-box;
 box-sizing: border-box;
}
html, body
{
 width: 100%;
 height: 100%;
 margin: 0;
 padding: 0;
 
 font-family: Arial, sans-serif;
}
pre, textarea 
{
 tab-size: 4;
 -moz-tab-size: 4;
 -o-tab-size: 4;
 -webkit-tab-size: 4;
}
textarea, pre
{
 width: 100%;
 min-height: 150px;
 
 padding: 4px;
}
.side-by-side-section
{
 display: flex;
}
.side-by-side-section > *
{
 flex: 1;
}
.code-block
{
 background: rgba(0, 0, 0, 0.1);
 border: 1px solid rgba(0, 0, 0, 0.2);
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Map keys" />
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//rawgit.com/wjbryant/taboverride/master/build/output/taboverride.js"></script>
<script src="//rawgit.com/wjbryant/jquery.taboverride/master/src/jquery.taboverride.js"></script>
 <meta charset="utf-8">
 <title>JS Bin</title>
</head>
<body>
<button class="go">Go</button>
Write data and conversion table in JSON.
<br />
<div class="side-by-side-section">
 <div>
 <div>Data:</div>
 <textarea class="data-box">
{
 "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
 }
 ]
} 
 </textarea>
 </div>
 <div>
 <div>Conversion table:</div>
 <textarea class="conversion-table-box">
{
 "psdf": "p", 
 "qwer": "q",
 "dict": {
 "_short": "d",
 
 "_object": {
 "one": "o",
 "two": "t",
 "three": "r"
 }
 },
 "candidates": {
 "_short": "c",
 "_array_item": {
 "ip": "i",
 "port": "p"
 }
 }
}
 </textarea>
 </div>
</div>
<div class="side-by-side-section">
 <div>
 <div>Converted:</div>
 <pre class="code-block"><code class="result"></code></pre>
 </div>
 <div>
 <div>Converted back:</div>
 <pre class="code-block"><code class="result-back-to-normal"></code></pre>
 </div>
</div>
</body>
</html>
Source Link
konijn
  • 34.2k
  • 5
  • 70
  • 267

Great question,

Can you take the truth?
The real answer is that this is overkill. Send your JSON to other machines/clients with HTTP compression (gzip) and the benefits of slimming down are close to non-existing.

Divide and conquer
Still, this is a fun question. After looking at this for a while, I've come to the conclusion that you have so much code because you tried too hard to apply DRY. Converting keys and reverting keys are different enough to deserve separate functions. They will look tantalizingly similar, but I am quite sure that merging them is wrong.

Naming convention
Furthermore, stop using _ and __ as prefixes to variables, it is not idiomatic for JavaScript. And start using lowerCamelCase, so __is_recursive_iteration should be isRecursiveIteration.

Name that thing
Furthermore, to quote Humpty Dumpty

"When I use a word," Humpty Dumpty said, in rather a scornful tone, "it means just what I choose it to mean—neither more nor less." "The question is," said Alice, "whether you can make words mean so many different things." "The question is," said Humpty Dumpty, "which is to be master—that's all." ― Lewis Carroll

When you declare curr_level_table_key it is the only 'key' in the scope, feel free to declare it simply as key, this would make your code far easier to understand. If you are not comfortable because it does not convey enough info, you could comment it (I would not do this personally):

var key = table_level_keys[i]; //Current level table key <- That does not really make sense to me

Commenting
Also your commenting is too excessive for what really should be a simple, recursive, key swapping algorithm. At least convert your 2 line comments to 1 line comments, remove obvious comments, and all remaining multi line comments should go in front of the function.

Worst offender:

 
// Break out of the for loop after we found it
break;

Avoid the arrow pattern
You know that things are getting too complex when you see the arrow pattern, like here:

 //console.log('next', next_conversion_level);
 recursiveConvertKeys(data_object, conversion_table, swap_conversion_table_key_value, true, value, next_conversion_level);
 }
 }
 }
 });
 }
}

In this particular case you can do this by using the continue statement if you know that nothing else must be done in the loop, so consider using

if (!object.hasOwnProperty(key)){
 continue;
}

Housekeeping
Remove commented out code, your code is already hard to read and follow.

Counter proposal

// from: http://stackoverflow.com/a/4648411/796832
// Check for the old property name to avoid a ReferenceError in strict mode.
function renameProperty(object, oldName, newName) {
 if (object.hasOwnProperty(oldName)) {
 object[newName] = object[oldName];
 delete object[oldName];
 return object[newName];
 }
}
function convertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).map(function(key) {
 var mappedKey = map[key];
 if (!mappedKey) {
 return;
 }
 var value = object[key];
 if (mappedKey instanceof Object) {
 if (mappedKey._short) {
 value = renameProperty(object, key, mappedKey._short);
 }
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 convertKeys(value[i], mappedKey._array_item);
 }
 } else if (value instanceof Object) {
 convertKeys(value, mappedKey._object);
 }
 } else {
 renameProperty(object, key, mappedKey);
 }
 });
}
function findValueKey(object, searchValue) {
 var keys = Object.keys(object), key, value;
 
 for (var i = 0, length = keys.length; i < length; i++) {
 key = keys[i];
 value = object[key]; 
 if (value === searchValue) {
 return key;
 }
 if( value instanceof Object && value._short == searchValue ){
 return key;
 }
 }
}
function revertKeys(object, map) {
 if (typeof object != "object") {
 return;
 }
 //Iterate over the object
 Object.keys(object).forEach(function(key) {
 var mappedKey = findValueKey(map, key);
 if (!mappedKey) {
 return;
 }
 var value = renameProperty(object, key, mappedKey),
 subMap = map[mappedKey];
 console.log( subMap );
 if (subMap instanceof Object) {
 if (value instanceof Array) {
 for (var i = 0, length = value.length; i < length; i++) {
 revertKeys(value[i], subMap._array_item);
 }
 } else if (value instanceof Object) {
 revertKeys(value, subMap._object);
 }
 }
 });
}
$('textarea').tabOverride();
$('.go').on('click', function() {
 // Tests
 // ---------------------------
 var data = JSON.parse($('.data-box').val());
 var conversion_table = JSON.parse($('.conversion-table-box').val());
 // Clone the data so we don't overwrite it
 var resultant_data = $.extend(true, {}, data);
 // Now execute the key converting process
 convertKeys(resultant_data, conversion_table);
 $('.result').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Reversed Data:", resultant_data);
 // If you want to reverse the process simply pass true for the `swap_conversion_table_key_value` argument
 revertKeys(resultant_data, conversion_table);
 $('.result-back-to-normal').html(JSON.stringify(resultant_data, null, '\t'));
 console.log("Back to normal Data:", resultant_data);
}).trigger('click');
*, *:before, *:after {
 -moz-box-sizing: border-box;
 -webkit-box-sizing: border-box;
 box-sizing: border-box;
}
html, body
{
 width: 100%;
 height: 100%;
 margin: 0;
 padding: 0;
 
 font-family: Arial, sans-serif;
}
pre, textarea 
{
 tab-size: 4;
 -moz-tab-size: 4;
 -o-tab-size: 4;
 -webkit-tab-size: 4;
}
textarea, pre
{
 width: 100%;
 min-height: 150px;
 
 padding: 4px;
}
.side-by-side-section
{
 display: flex;
}
.side-by-side-section > *
{
 flex: 1;
}
.code-block
{
 background: rgba(0, 0, 0, 0.1);
 border: 1px solid rgba(0, 0, 0, 0.2);
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Map keys" />
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//rawgit.com/wjbryant/taboverride/master/build/output/taboverride.js"></script>
<script src="//rawgit.com/wjbryant/jquery.taboverride/master/src/jquery.taboverride.js"></script>
 <meta charset="utf-8">
 <title>JS Bin</title>
</head>
<body>
<button class="go">Go</button>
Write data and conversion table in JSON.
<br />
<div class="side-by-side-section">
 <div>
 <div>Data:</div>
 <textarea class="data-box">
{
 "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
 }
 ]
} 
 </textarea>
 </div>
 <div>
 <div>Conversion table:</div>
 <textarea class="conversion-table-box">
{
 "psdf": "p", 
 "qwer": "q",
 "dict": {
 "_short": "d",
 
 "_object": {
 "one": "o",
 "two": "t",
 "three": "r"
 }
 },
 "candidates": {
 "_short": "c",
 "_array_item": {
 "ip": "i",
 "port": "p"
 }
 }
}
 </textarea>
 </div>
</div>
<div class="side-by-side-section">
 <div>
 <div>Converted:</div>
 <pre class="code-block"><code class="result"></code></pre>
 </div>
 <div>
 <div>Converted back:</div>
 <pre class="code-block"><code class="result-back-to-normal"></code></pre>
 </div>
</div>
</body>
</html>

default

AltStyle によって変換されたページ (->オリジナル) /