在Javascript中模拟map/set

7
我有一个json对象,比如说box = {};,我会不断地添加键值对,例如box['somename'] = somevalue。可能会有重复的somename,我希望最后一个实例的值能够获胜。这一切都没问题。
现在我需要像操作数组一样操作它。基本上,既然我有了一组唯一的键,我想要一个主要操作box.length来查看有多少个唯一元素。是否有一种优雅的常数时间方式来做到这一点,而不必遍历该对象的所有属性?

1
可能是如何高效地计算JavaScript对象中键/属性的数量?的重复问题。 - Lightness Races in Orbit
是的,看起来是这样,但这里的答案更好,你觉得呢 :) - Sanjeev Satheesh
2个回答

9
var box = { 
  length: 0,
  add: function(k, v) {
    if (typeof this[k] === 'undefined')
      this.length++;
    this[k] = v;
  }
}

1
在进行赋值之前,您还应该检查 k != "length" - Jan
@Jan:没错,如果k是"length"或者box的任何其他特殊属性,add方法可能应该引发一个错误。 - Eric Mickelsen
2
如果您删除一个键/值对(delete box[somekey]),会发生什么? - KooiInc
@Kooilnc:delete: function(k) { if (typeof this[k] !== 'undefined') this.length--; delete this[k]; } - Eric Mickelsen
@Eric Mickelsen:如果你不使用add(box.somenewkey='directset'),该怎么办? - KooiInc
1
@Kooilnc:在这种情况下,无论如何你都没有办法。在Javascript中,没有办法防止这种情况发生。假设你会一贯地使用提供的函数。 - Eric Mickelsen

4
每当你向box中添加新元素时,计数器就会增加。
function Box() {
    var length = 0;
    var items = {};
    this.add = function(k, v) {
        if (!(k in items))
            length++; // don't count twice
        items[k] = v;
    }
    this.get = function(k) {
        return items[k];
    }
    this.delete = function(k) {
        if (k in items)
            length--; 
        delete items[k];
    }
    this.__defineGetter__("length", function() { 
        return length; 
    });
}

这个版本可以正确地处理添加和删除任何名称的元素,并提供只读访问length属性。使用方法:

var box = new Box();
box.add("a", 1);
box.add("a", 2); // overwrite
box.add("b", "whatever");
box.add(null, 3);
box.add(undefined, 3);
box.add(undefined, 42);
box.add("", 41);
console.log(box.length); // 5
console.log(box.get(undefined)); // 42 
console.log(box.get(null)); // 3 
console.log(box.get("")); // 41
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(22); // never was defined
console.log(box.length); // 4
console.log(box.get(undefined)); // undefined 
box.add("length", "33") 
box.add("items", "jfhsdjkfh"); 
box.add("length", 77);
console.log(box.length); // 6

@Eric - 已修复,但我仍然喜欢你的解决方案。更加符合JavaScript的风格。 - Wayne
可能有点挑剔,但是你的方法更健壮,因为值本身可以是 undefined。调用多次 box.addItem("a", undefined) 不会增加 length。+1 - Anurag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接