使用对象数组构造一个新对象,该对象将调用原始数组中声明的函数

时间:2017-07-16 08:13:53

标签: javascript arrays object

我正在为我的新网站项目使用JS路由器。路由器接受一个对象:Key是URL地址,Value是一个在到达地址时被调用的函数。

随着页面数量和子页面越来越大,它变得越来越混乱,特别是考虑到不同的页面需要调用不同的初始化函数(initAccordioninitDataTables等等)。 / p>

为了保持整洁我想到了创建一个对象数组,这些对象将保存页面名称和加载页面后需要调用的init函数。但是,我使用的解决方案使用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

这一切都很好,但有没有办法让pages.init数组没有引号而对象创建者不使用eval?因此,值看起来像init: [initFoo, initBar]

所以我的问题确实是:有没有一种方法可以创建新的routerPaths对象而无需构造字符串然后在其上运行eval?我应该坚持我拥有的东西吗?

请注意,routerPaths.homerouterPaths.people必须是调用pages.init中函数的函数。

2 个答案:

答案 0 :(得分:1)

不需要通过字符串名称引用函数。只需像任何其他变量一样使用函数名称。     var pages = [         {             名称:" home",             init:[initFoo,initBar]         },         {             名字:"人物",             init:[initBar]         }     ];

并将您的init存根编写为普通的闭包(注意:在循环中使用let而不是var是必须的。)

var routerPaths = {};

for (var page of pages) {
    let init = page.init;

    routerPaths[page.name] = function() {
        init.forEach(function(fn) { fn() })
    }
}

如果您无法使用ES6 for...oflet,请将其替换为`forEach:

pages.forEach(function(page) {
    var init = page.init;
    routerPaths[page.name] = function() {
        init.forEach(function(fn) { fn() })
    }
})

答案 1 :(得分:0)

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