Reputation: 479
I am using a JS router for my new website project. The router accepts an object: the Key is the URL address and the Value is a function that will get called when the address is reached.
It gets messy pretty quickly with the amount pages and sub pages growing bigger and bigger, especially considering that different pages need to call different initialization functions (initAccordion
or initDataTables
, etc, etc).
Just to keep it neat I thought of creating an array of objects that will hold the page names and the init functions that need to be called after the page is loaded. However the solution I use uses eval
:
function initFoo() {
console.log("initFoo says hi");
}
function initBar() {
console.log("initBar says hi");
}
var pages = [
{
name: "home",
init: ["initFoo", "initBar"]
},
{
name: "people",
init: ["initBar"]
}
];
var routerPaths = {};
for (var page in pages) {
var url = pages[page].name;
var init = pages[page].init;
// construct the string for eval()
var objStr = "routerPaths['" + url + "'] = function() {";
for(var item in init) {
objStr += init[item] + "();";
}
objStr += "};";
eval(objStr);
}
routerPaths.home(); // as expected: initFoo says hi initBar says hi
routerPaths.people(); // as expected: initBar says hi
This all fine, but is there a way to perhaps have the pages.init
array without the quotes and the object creator NOT using eval
? So that the values would look like this init: [initFoo, initBar]
.
So my questions really are: Is there a way of creating the new routerPaths
object without constructing a string and then running eval
on it? Should I just stick with what I have?
Keep in mind that routerPaths.home
, routerPaths.people
need to be functions that call the functions from pages.init
.
Upvotes: 0
Views: 41
Reputation: 214949
There's no need to reference functions by their string names. Just use a function name like any other variable. var pages = [ { name: "home", init: [initFoo, initBar] }, { name: "people", init: [initBar] } ];
and write your init
stubs as ordinary closures (note: it's imperative to use let
and not var
in the loop).
var routerPaths = {};
for (var page of pages) {
let init = page.init;
routerPaths[page.name] = function() {
init.forEach(function(fn) { fn() })
}
}
If you can't use ES6 for...of
and let
, replace them with `forEach:
pages.forEach(function(page) {
var init = page.init;
routerPaths[page.name] = function() {
init.forEach(function(fn) { fn() })
}
})
Upvotes: 1
Reputation: 104
const initFoo=()=>{
console.log("initFoo says hi");
}
const initBar=()=> {
console.log("initBar says hi");
}
let pages = [
{
name: "home",
init: [initFoo, initBar]
},
{
name: "people",
init: [initBar]
}
];
let routerPaths = {
};
for (let page in pages) {
let url = pages[page].name;
let init = pages[page].init;
Object.defineProperty( routerPaths , url , {
value: ()=>{
for(var item in init) {
init[item]();
}
},
enumerable: true, // if enumerable is true then only you can see the people,home properties if you console.log
//if enumerable set to false you can not see the the property but you can still call routerPaths.people and it just works fine
});
}
console.log(routerPaths);
routerPaths.home(); // as expected: initFoo says hi initBar says hi
routerPaths.people(); // as expected: initBar says hi
Upvotes: 0