EN
JavaScript - convert object to JSON with ordered properties
5
points
In this article we would like to show how in JavaScript create JSON from object that has ordered properties.
Quick solution:
// ONLINE-RUNNER:browser;
const isArray = object => object instanceof Array;
const iterateKeys = (object, callback) => {
const entries = Object.entries(object);
entries.forEach(([key, value]) => {
callback(key, value);
if (typeof value === 'object') {
iterateKeys(value, callback);
}
});
};
const getKeys = (object) => {
const keys = [];
iterateKeys(object, (key, value) => keys.push(key));
return keys;
};
const stringifyObject = (object, indent) => {
const keys = getKeys(object).sort();
return JSON.stringify(object, keys, indent);
};
// Usage example:
const indent = ' ';
const object = {
"name": "John", // <-------- will be moved to 2nd position
"age": 25, // <------------- will be moved to 1st position
"todos": [
"Lectures",
"Classes"
]
};
const json = stringifyObject(object, indent);
console.log(json);
Custom implementation
The solution in below example sorts properies before stringify operation.
Practical example:
// ONLINE-RUNNER:browser;
const compareStrings = (a, b) => {
if (a < b) return -1;
if (a > b) return +1;
return 0;
};
const escapeText = (text) => {
let result = '';
for (let i = 0; i < text.length; ++i) {
const code = text.charCodeAt(i);
switch (code) {
case 0x00: // \0 - NULL
case 0x01: case 0x02: case 0x03: case 0x04:
case 0x05: case 0x06: case 0x07: case 0x08:
continue;
case 0x09: // \t - TABULATOR
result += '\\t';
continue;
case 0x0A: // \n - NEW LINE
result += '\\n';
continue;
case 0x0B: case 0x0C:
continue;
case 0x0D: // \r - CARRIAGE RETURN
result += '\\r';
continue;
case 0x0E: case 0x0F: case 0x10: case 0x11:
case 0x12: case 0x13: case 0x14: case 0x15:
case 0x16: case 0x17: case 0x18: case 0x19:
case 0x1A: case 0x1B: case 0x1C: case 0x1D:
case 0x1E: case 0x1F:
continue;
// allowed characters: 0x20 and 0x21
case 0x22: // " - DOUBLE QUOTATION MARK
result += '\\"';
continue;
// allowed characters: 0x23 - 0x26
case 0x27: // ' - SINGLE QUOTATION MARK
result += '\'';
continue;
// allowed characters: 0x28 - 0x5B
case 0x5C: // \ - BACK SLASH
result += '\\\\';
continue;
default:
result += text[i];
}
}
return result;
};
const getType = (object) => {
return Object.prototype.toString.call(object);
};
const prettifyArray = (array, prefix, indent) => {
let result = '[\n';
for (let i = 0; i < array.length; ++i) {
const value = prettifyEntry(array[i], prefix + indent, indent);
if (i > 0) {
result += ',\n'
}
result += prefix + indent + value;
}
return result + '\n' + prefix + ']';
};
const prettifyObject = (object, prefix, indent) => {
let result = '{\n';
const entries = Object.entries(object).sort(compareStrings);
for (const entry of entries) {
const name = escapeText(entry[0]);
const value = prettifyEntry(entry[1], prefix + indent, indent);
if (result.length > 2) {
result += ',\n'
}
result += prefix + indent + '"' + name + '": ' + value;
}
return result + '\n' + prefix + '}';
};
const prettifyEntry = (entry, prefix, indent) => {
const type = getType(entry);
switch(type) {
case '[object Array]':
return prettifyArray(entry, prefix, indent);
case '[object Object]':
return prettifyObject(entry, prefix, indent);
case '[object Null]':
return null;
case '[object Boolean]':
case '[object Number]':
case '[object BigInt]':
return entry;
case '[object String]':
return '"' + escapeText(entry) + '"';
default:
throw new Error(type + ' type is not permitted in json.');
}
};
const stringifyObject = (object, indent) => {
return prettifyEntry(object, '', indent || '\t');
};
// Usage example:
const indent = ' ';
const object = {
"name": "John",
"age": 25,
"todos": [
"Lectures",
"Classes"
]
};
const json = stringifyObject(object, indent);
console.log(json);