I am doing this on the client with Javascript. I want to transform:
[
{
"id": 10,
"name": "Designer",
"slug": "designer",
"children": [
{
"id": 11,
"name": "UI / Visual Designer",
"slug": "ui-visual-designer",
"children": []
},
...
]
},
{
"id": 1,
"name": "Software Engineer",
"slug": "software-engineer",
"children": [
{
"id": 2,
"name": "Back-End Developer",
"slug": "back-end-developer",
"children": []
},
...
]
},
...
]
into this:
[
{
"id": 10,
"text": "Designer"
},
{
"id": 11,
"text": "UI / Visual Designer",
},
{
"id": 1,
"text": "Software Engineer",
},
{
"id": 2,
"text": "Back-End Developer",
}
...
]
I am practicing with map
and reduce
so I am trying to avoid for
loops (first thing I did). This is the current code I have:
var jobNewPage = {
...
buildArrayForSelect(array) {
"use strict";
return $.extend(true, [], array).reduce(function(total, item) {
if ( item.slug == 'remote' ) return total;
total.push({
'id' : item.id,
'text' : item.name
});
let children = item.children;
if (children && children.length) {
// TODO: We had to call the global context jobNewPage
total = total.concat(jobNewPage.buildArrayForSelect(children));
}
return total;
}, []);
},
...
}
So, as you can see, I have had to call jobNewPage.buildArrayForSelect(children)
to do it recursively. I tried to call this.buildArrayForSelect(children)
but the context is different. I feel this is not the best option because I don't want to depend calling a global variable inside a function in the object. How can I improve it?
reduce(function(done,curr){if the previous line is true and the argument is an array, we want to reduce it. This is our recursive case.
reduce will return the only value (object or otherwise) if the list object only has one item, without calling iterator function.
To prevent infinite recursion, you can use if...else statement (or similar approach) where one branch makes the recursive call, and the other doesn't. So, it generally looks like this. function recurse() { if(condition) { recurse(); } else { // stop calling recurse() } } recurse();
To create an array (or object) using reduce, we first must pass in an empty array (or object if we see fit) as the initial value. Then within each step of reduce, we perform the desired operation on the passed in array (or object) and return the newly mutated array (or object).
It seems your question boils down to how to recursively call a function from within itself, when that function is defined using a function expression and assigned to a property on a higher-scoped object.
The simple answer is to turn it into a named function expression. Such functions are are able to call themselves recursively:
var obj = {
myMethod: function myName(n) { //function expression has name "myName"...
console.log(n);
if (n > 0)
myName(n-1); //...which we can use inside the function...
}
}
//...and outside we refer to the object's property name
obj.myMethod(5);
This approach, applied to your object and function, would look as follows:
var jobNewPage = {
//give the function expression a name:
buildArrayForSelect: function buildArrayForSelect(array) {
"use strict";
return $.extend(true, [], array).reduce(function(total, item) {
if ( item.slug == 'remote' ) return total;
total.push({
'id' : item.id,
'text' : item.name
});
let children = item.children;
if (children && children.length) {
//No need to reference object to call the function recursively:
total = total.concat(buildArrayForSelect(children));
}
return total;
}, []);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With