I made a FIDDLE for you. I am storing a stack string and then output it, if the property is of primitive type:
function iterate(obj, stack) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
} else {
console.log(property + " " + obj[property]);
$('#output').append($("<div/>").text(stack + '.' + property))
}
}
}
}
iterate(object, '')
Update: 17/01/2019
There used to be a different implementation, but it didn't work. See this answer for a prettier solution
Answer from Artyom Neustroev on Stack OverflowI made a FIDDLE for you. I am storing a stack string and then output it, if the property is of primitive type:
function iterate(obj, stack) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
} else {
console.log(property + " " + obj[property]);
$('#output').append($("<div/>").text(stack + '.' + property))
}
}
}
}
iterate(object, '')
Update: 17/01/2019
There used to be a different implementation, but it didn't work. See this answer for a prettier solution
The solution from Artyom Neustroev does not work on complex objects, so here is a working solution based on his idea:
function propertiesToArray(obj) {
const isObject = val =>
val && typeof val === 'object' && !Array.isArray(val);
const addDelimiter = (a, b) =>
a ? `
{b}` : b;
const paths = (obj = {}, head = '') => {
return Object.entries(obj)
.reduce((product, [key, value]) =>
{
let fullPath = addDelimiter(head, key)
return isObject(value) ?
product.concat(paths(value, fullPath))
: product.concat(fullPath)
}, []);
}
return paths(obj);
}
const foo = {foo: {bar: {baz: undefined}, fub: 'goz', bag: {zar: {zaz: null}, raz: 3}}}
const result = propertiesToArray(foo)
console.log(result)
EDIT (2023/05/23):
4 different (complete) solutions with full descriptions are available on LeetCode: https://leetcode.com/problems/array-of-objects-to-matrix/editorial/?utm_campaign=PostD19&utm_medium=Post&utm_source=Post&gio_link_id=EoZk0Zy9
javascript - JS Recursive object assign - Stack Overflow
recursion - javascript object recursive function - Stack Overflow
recursion - Recurse over a object - Javascript - Stack Overflow
javascript - Generated recursive object based on array - Stack Overflow
in object literal notation that you used to define object, avoid using this because this refers to window object. Instead you can used object name of which you are creating property like.
var obj = {
testfunction: function() {
obj.testfunction();
}
};
The best way to ensure you calling the right function is not to depend on this and not to use anonymous function. Give you function a temporary name and call it like this.
var obj ={
fun : function Q(a){
if(a>0){
return Q(a-1) + a;
}
return 0;
}
}
It is a common practice to call it with one capital letter if you will only call it by this name for recursion.
Try and always give your functions a name as it is easier to debug this way (function name will appear in call trace)
Please note that using recursion in javascript can be dangerous as javascript doesn't have tail-call optimization and you can run to stack overflow easily if you're not carefull.
You can use reduce() method and as accumulator pass object that you want add properties to.
var arr = ['one', 'two', 'three']
var obj = {}
arr.reduce(function(r, e, i) {
r.path = e;
return arr[i+1] ? r.nested = {} : r
}, obj)
console.log(obj)
Run code snippetEdit code snippet Hide Results Copy to answer Expand
If you want to use just recursion without loop you can create function like this.
var data = ['one', 'two', 'three']
var obj = {}
function makeObj(arr, n, o) {
if (n == arr.length - 1) o.path = arr[n]
else {
o.path = arr[n];
o.nested = {}
makeObj(arr, n += 1, o.nested)
}
return o.nested
}
makeObj(data, 0, obj)
console.log(obj)
Run code snippetEdit code snippet Hide Results Copy to answer Expand
var arr = ['one', 'two', 'three'];
var tree = arr.reduceRight((nested, path) => {
return nested? {path, nested}: {path};
}, null);
console.log(tree);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
or even better/simpler, just:
var arr = ['one', 'two', 'three'];
var tree = arr.reduceRight((nested, path) => ({path, nested}), null);
console.log(tree);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
It simplifies things for the JS engine if all objects have the same hidden class (simplified: same property names).
You could use a destructuring assignment for the wanted keys and use Array#map for getting a new array with only the one property and use Object.assign for the children objects by checking the children and if exist, take the urls from the children with a recursive call of the function.
function getUrls(array) {
return array.map(({ url, children }) =>
Object.assign({ url }, children && { children: getUrls(children) }));
}
var settings = [{ path: '/templates/pictures.php', url: '/pictures', label: 'Pictures', component: 'tab', template: 'default' }, { path: '/templates/post-article.php', url: '/user/:username', component: 'table', template: 'default', children: [{ path: '/templates/post-article-highlights.php', url: '/user/:username/highlights', component: 'table', template: 'default', children: [{ path: '/templates/post-article-highlights.php', url: '/user/:username/highlights', component: 'table', template: 'default' }] }] }],
urls = getUrls(settings);
console.log(urls);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const settings = [
{path: '/templates/pictures.php', url: '/pictures', label: 'Pictures', component: 'tab', template: 'default'},
{path: '/templates/post-article.php', url: '/user/:username', component: 'table', template: 'default', children:[
{path: '/templates/post-article-highlights.php', url: '/user/:username/highlights', component: 'table', template: 'default', children:[
{path: '/templates/post-article-highlights.php', url: '/user/:username/highlights', component: 'table', template: 'default'}
]}
]}
];
function childrenUrls(childrens){
return childrens.reduce(function(arr, obj){
var newObj = {url: obj.url};
if(obj.children) newObj.children = childrenUrls(obj.children);
return arr.push(newObj), arr;
}, []);
}
const newArray = childrenUrls(settings);
console.log(newArray);