如何有效地索引到Javascript对象?

时间:2018-02-11 07:52:50

标签: javascript jquery dom

人们是否曾使用基于DOM的数据存储/检索而不是数组或对象来使索引更简单?

考虑下面的代码段。要将颜色更新为棕色,无论name = Bob在Javascript中需要两个循环:一个用于团队,一个用于玩家。然后进行比较以在进行颜色更改之前检查name = Bob。



var obj = {"team1": {
  "player1": {
    "name": "bob",
    "color": "red",
  },
  "player2": {
    "name": "george",
    "color": "blue",
  },
},
"team2": {
  "player1": {
    "name": "bob",
    "color": "orange",
  },
  "player2": {
    "name": "george",
    "color": "green",
  },
}};

for (var i in obj)
  for (var j in obj[i])
    if (obj[i][j]["name"] == 'bob')
      obj[i][j]["color"] = 'brown';
      
console.log(obj); // color changed to brown for the two bobs




但是如果数据存储在DOM中,则在表格单元格"数据"例如,使用一行jQuery更新name = bob的颜色更容易:

$("td[data-name='bob']").data("color", "brown");

我的javascript对象有大约1000个团队,每个团队有4-5个玩家。为每种颜色变化循环整个事情似乎需要很多开销。而jQuery似乎能够将整个DOM保存在内存中(真正的陈述?)并直接切换到正确的单元格并进行颜色更改。

或者,为了做出改变,jQuery实际上必须在幕后执行两个循环(或类似的性能成本)?

1 个答案:

答案 0 :(得分:2)

执行$("td[data-name='bob']")时,必须迭代DOM。与此相比,数据对象的循环非常轻。与在对象结构中执行简单更新相比,更新DOM中的属性的时间要长得多。因此,您需要为看起来容易的事情付出代价。

两个循环确实没有问题:重要的是你需要访问的条目数。

如果您经常需要根据播放器名称进行更新,那么您可以考虑甚至添加类似索引的数据结构,以便通过名称更快地访问:



const obj = {"team1": {"player1": {"name": "bob","color": "red"},"player2": {"name": "george","color": "blue"}},"team2": {"player1": {"name": "bob","color": "orange"},"player2": {"name": "george","color": "green"}}};
    
// Create a structure keyed by name
const byName = {};
for (const [team, players] of Object.entries(obj)) {
    for (const [playerId, player] of Object.entries(players)) {
        byName[player.name] = 
            (byName[player.name] || []).concat({team, playerId, player});
    }
}

function updateColorForName(name, color) {
    for (const info of byName[name]) {
        info.player.color = color;
    }
}

// Sample call:
updateColorForName("bob", "brown");
// Show update:
console.log(obj);

.as-console-wrapper { max-height: 100% !important; top: 0; }




要进一步使用ES6电源,请使用更合适的Map

实现上述功能



const obj = {"team1": {"player1": {"name": "bob","color": "red"},"player2": {"name": "george","color": "blue"}},"team2": {"player1": {"name": "bob","color": "orange"},"player2": {"name": "george","color": "green"}}};
    
// Create a Map keyed by name
const byName = new Map();
for (const [team, players] of Object.entries(obj)) {
    for (const [playerId, player] of Object.entries(players)) {
        byName.set(player.name, 
            (byName.get(player.name) || []).concat({team, playerId, player}));
    }
}

function updateColorForName(name, color) {
    for (const info of byName.get(name)) {
        info.player.color = color;
    }
}

// Sample call:
updateColorForName("bob", "brown");
// Show update:
console.log(obj);

.as-console-wrapper { max-height: 100% !important; top: 0; }