Skip to content

Instantly share code, notes, and snippets.

@donatoaz
Forked from creationix/extract-closure.js
Created May 14, 2018 18:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donatoaz/7423fbef100cf4060fcf77ee59a02ddc to your computer and use it in GitHub Desktop.
Save donatoaz/7423fbef100cf4060fcf77ee59a02ddc to your computer and use it in GitHub Desktop.
Key extractor that supports nested objects, nested arrays, duplicate keys, and cycles, returning an array of the unique keys.
// All of these should return the keys "a", "b", "c"
var inputs = [
{a:1,b:2,c:3}, // Simple object
{a:{b:2,c:3}}, // Simple object with nesting
{a:{a:{b:2,c:3}}}, // Repeated key hiding nesting
{a:[{b:2,c:3}]}, // keys behind array
];
inputs.push(inputs); // reference cycle and array at top
function getKeys(obj) {
var all = {};
var seen = [];
checkValue(obj);
return Object.keys(all);
function checkValue(value) {
if (Array.isArray(value)) return checkArray(value);
if (value instanceof Object) return checkObject(value);
}
function checkArray(array) {
if (seen.indexOf(array) >= 0) return;
seen.push(array);
for (var i = 0, l = array.length; i < l; i++) {
checkValue(array[i]);
}
}
function checkObject(obj) {
if (seen.indexOf(obj) >= 0) return;
seen.push(obj);
var keys = Object.keys(obj);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
all[key] = true;
checkValue(obj[key]);
}
}
}
var result = inputs.map(getKeys);
console.log(result);
// All of these should return the keys "a", "b", "c"
var inputs = [
{a:1,b:2,c:3}, // Simple object
{a:{b:2,c:3}}, // Simple object with nesting
{a:{a:{b:2,c:3}}}, // Repeated key hiding nesting
{a:[{b:2,c:3}]}, // keys behind array
];
inputs.push(inputs); // reference cycle and array at top
function getKeys(obj) {
var all = {};
var seen = [];
checkValue(obj, all, seen);
return Object.keys(all);
}
function checkValue(value, all, seen) {
if (Array.isArray(value)) return checkArray(value, all, seen);
if (value instanceof Object) return checkObject(value, all, seen);
}
function checkArray(array, all, seen) {
if (seen.indexOf(array) >= 0) return;
seen.push(array);
for (var i = 0, l = array.length; i < l; i++) {
checkValue(array[i], all, seen);
}
}
function checkObject(obj, all, seen) {
if (seen.indexOf(obj) >= 0) return;
seen.push(obj);
var keys = Object.keys(obj);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
all[key] = true;
checkValue(obj[key], all, seen);
}
}
var result = inputs.map(getKeys);
console.log(result);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment