2017-07-16 17 views
0

我正在爲我的新網站項目使用JS路由器。路由器接受一個對象:Key是URL地址,Value是一個在到達地址時會被調用的函數。使用一個對象數組構造一個新對象,該對象將調用在原始數組中聲明的函數

隨着頁面和子頁面的數量越來越大,特別是考慮到不同的頁面需要調用不同的初始化函數(initAccordioninitDataTables等等),它變得非常混亂。

爲了保持它整潔,我想創建一個對象數組,它將保存頁面名稱和加載頁面後需要調用的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.home,routerPaths.people需要是從pages.init調用函數的函數。

回答

1

沒有必要通過字符串名稱來引用函數。只需像使用其他變量一樣使用函數名稱即可。 VAR頁= [ { 名: 「家」, 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() }) 
    } 
}) 
+0

這是我使用的是前端路由器。您的解決方案是否可以在瀏覽器中運行? –

+0

@DamianChrzanowski:爲舊版瀏覽器添加了一個示例 – georg

+0

好吧,不好給它一個去 –

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 
相關問題