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 isObject = (entry) => typeof entry === 'object';
const iterateKeys = (entry, callback) => {
const keys = Object.keys(entry);
for (const key of keys) {
callback(key, entry[key]);
};
};
const findKeys = (entry) => {
if (isObject(entry)) {
const keys = [];
const callback = (key, value) => {
keys.push(key);
if (isObject(value)) {
iterateKeys(value, callback);
}
};
iterateKeys(entry, callback);
return keys.sort();
}
return null;
};
const toJson = (object, indent) => {
const keys = findKeys(object);
return JSON.stringify(object, keys, indent);
};
// Usage example:
const indent = ' ';
const object = {
name: 'John', // <-------- it will be moved to 2nd position
age: 25, // <-------- it will be moved to 1st position
todos: [
'Lectures',
'Classes'
]
};
const json = toJson(object, indent);
console.log(json);
Custom implementation
The solution in below example sorts properies before stringify operation.
Practical example:
// ONLINE-RUNNER:browser;
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 keys = Object.keys(object);
for (const key of keys.sort()) {
const name = escapeText(key);
const value = prettifyEntry(object[key], 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);