2014-12-02 58 views
0

我有了項目類型和ID的JSON對象運行從字符串JavaScript對象,我需要創建新的對象如何在不使用eval()

var data = { 
      "items":[ 
        {"type":"generator","id":"item_1","x":200,"y":200}, 
        {"type":"battery","id":"item_2","x":50,"y":300}, 
        {"type":"generator","id":"item_3","x":200,"y":280}, 
        {"type":"battery","id":"item_4","x":100,"y":400} 
       ] 
     }; 

,我需要在項目的每一項運行

jQuery.each(data.items, function(index,value) { 
    eval("var " + value.id + " = new " + value.type + "(" + (index + 1) + ");"); 
    eval(value.id + ".id = '" + value.id + "';"); 
    eval(value.id + ".draw(" + value.x + "," + value.y + ");") 
}); 

這不是一個好習慣,但我還能做什麼?

我需要再有

item_1.moveto(300,700); 

,但我總是得到ITEM_1是undefind

回答

2

您可以創建一個工廠方法,它允許對項目的控制從抽象數據結構生成具體類型:

var createItem = (function() { 
    var types = {}; 

    function createItem(index, data) { 
     data = data || {}; 

     var ctor = types[data.type], item; 

     if (!ctor) throw new Error("'" + data.type + "' is not a registered item type."); 

     item = new ctor(index); 

     item.id = data.id; 

     return item; 
    } 

    createItem.registerType = function (type, ctor) { 
     types[type] = ctor; 
    }; 

    return createItem; 

})(); 

然後註冊項目類型工廠:

function Generator(index) {/*...*/} 

createItem.registerType('generator', Generator); 

最後創建一個對象地圖通過ID查找您的物品(你可以使用像ItemsMap,而不是一個普通的對象一個專門的對象),遍歷您的項目並將它們添加到地圖中。

var itemsMap = {}; 

data.items.forEach(function (itemData, i) { 
    var item = itemsMap[itemData.id] = createItem(i + 1, itemData); 

    //you can also draw them at this point 
    item.draw(itemData.x, itemData.y); 
}); 

您可以通過ID像現在查找對象:

var item1 = itemsMap['item_1']; 
+0

這是一個非常好的模式。是不是更好地移除registerType函數並將類型函數(即Generator等)直接移動到匿名函數中? (如果不在外面使用) – 2014-12-03 01:01:23

+0

另外,如果在forEach中使用「this [itemData.id] = createItem(i + 1,itemData)」,則可以刪除itemsMap對象並直接調用「item_1」。 – 2014-12-03 01:06:57

+0

@plbsam使用模塊模式可以認爲是,但是在forEach中使用'this'會污染全局名稱空間,所以它不是一個選項。您不想爲每個項目創建一個全局變量。 – plalx 2014-12-03 02:46:01

2
var objects = {}; 

objects[value.id] = new window[value.type](index + 1); 
+0

這是怎麼回事:像'generator'全局變量是真正的全球性對象,這在瀏覽器是'窗口的屬性'。所以普通的'generator'就意味着和'window.generator'一樣的東西。點語法只是當字段名稱符合標識符(變量名稱)的模式時可以使用的括號語法的快捷方式,所以'window.generator'與'window ['generator']'完全相同。這意味着如果'value.type'包含字符串''generator'','window [value.type]'自動與'generator'文字具有相同的功能。不需要'eval'。 – 2014-12-02 21:43:40

+0

那我怎麼叫對象呢?我嘗試item_1 – eyalb 2014-12-02 22:13:44

+0

如果函數沒有在窗口而是在另一個函數中定義,該怎麼辦?它不應該是這個[value.type]嗎? @SLaks – 2014-12-03 00:00:52