Javascript 使用等效对象引用对象内对象的索引。indexOf

Javascript 使用等效对象引用对象内对象的索引。indexOf,javascript,object,reference,indexof,Javascript,Object,Reference,Indexof,我很惊讶,我在StackOverflow上找不到这个问题的答案(也许我搜索得不对) 但基本上我很想知道是否有类似于Array.indexOf()方法的东西,但对于对象。也就是说,返回现有对象中值的索引的有效方法 例如,假设我有一个对象: var obj = { prop1: "a", prop2: "b", prop3: "c", prop4: "a" }; 现在我想找到包含“a”的索引,最好做一个obj.indexOf(“a”),让它返回类似[“prop1”,“prop4”] 但这似乎不是对

我很惊讶,我在StackOverflow上找不到这个问题的答案(也许我搜索得不对)

但基本上我很想知道是否有类似于Array.indexOf()方法的东西,但对于对象。也就是说,返回现有对象中值的索引的有效方法

例如,假设我有一个对象:

var obj = { prop1: "a", prop2: "b", prop3: "c", prop4: "a" };
现在我想找到包含“a”的索引,最好做一个
obj.indexOf(“a”)
,让它返回类似
[“prop1”,“prop4”]

但这似乎不是对象的实现方法

或者,我知道我可以创建一个函数:

function indexOf(val, obj){
  var indexes = [];

  for (var index in obj){
      if(!obj.hasOwnProperty(index)) continue;

      if(obj[index] == val){
        indexes.push(index);
      }   
   }

   if(!indexes.length) return false;
   else return indexes;
}

indexOf("a", obj); // returns ["prop1","prop4"]
但是这样迭代整个对象感觉很笨拙!!我将要处理的一些对象将相当大,并且值也可能相当大


有更好、更有效的方法吗?

如果你有一个非常大的对象,你可以使用复杂度为O(1)的nice来存储每个对象的密钥。因此,您必须实现哈希集合,因此在设置键值对时,还需要将密钥存储在weakmap中。 我还做了一些长凳。此自定义HashMap与RawObject搜索的比较-

WeakMap在其核心中使用了
Object.defineProperty
方法。因此,存在一些限制:

  • 浏览器:IE9+
  • 在上面的HashMap示例中,对象作为值,因为它们在WeakMap集合中用作键

但是这种方法极大地提高了性能,因为不需要迭代对象来寻找特定的值

也许你应该重新设计你的数据结构,这样你就不需要这样做了?您需要经常搜索的任何内容都应该是键,而不是值。搜索的问题可能是您查找的是索引而不是属性。
for..in
是您唯一的选择。我会在里面放一个hasOwnProperty测试,这样你就不会得到继承的属性了。@RobG True,谢谢!更新了代码。超级有趣!我不太清楚这是怎么回事。当我尝试在我的场景中使用它时,似乎不能使用字符串作为键?进一步挖掘后,似乎只允许将对象用作键?我想知道这是否适用于作为值的函数……是的,从上面的示例中,您不能使用原语,例如字符串、值中的数字,但对象和函数可以-这就是weakmap限制。但是您可以将任何字符串转换为对象-
str=newstring(str)
。这工作非常简单-我们使用WeakMap shim-这是一个集合,我们可以将对象和函数作为键。因此,我们将数据存储在两个集合中:
property:value
(字符串:对象/函数)和
value:properties
(对象/函数:数组)。所以我们有更好的性能,当我们需要得到一个值的所有键-O(1)而不是O(n)时,我刚刚尝试了这个方法,效果非常好!请更新您的答案,包括限制和如何使用此方法的进一步解释。然后我会选择它,因为它似乎是一种非常有效的方法。我还创建了一个jsperf测试用例(使用您的代码)。我尝试的另一种方法是创建一组索引数组,但也针对标准迭代进行了测试。它在浏览器间运行的速度真是太快了!!Firefox使用哈希映射的速度非常快。
function HashMap() {
    this.__map = new WeakMap;
    this.__hash = {};
}

HashMap.prototype = {
    set: function(key, value){
        this.unset(key);

        if (value == null) 
            return;

        this.__hash[key] = value;

        var keys = this.__map.get(value);
        if (keys == null) 
            this.__map.set(value, keys = []);

        keys.push(key);
    },
    unset: function(key){
        var value = this.__hash[key];
        if (value) {

            var keys = this.__map.get(value),
                index = keys.indexOf(key);

            keys.splice(index, 1);
        }
        this.__hash[key] = void 0;
    },

    get: function(key){
        return this.__hash[key];
    },
    getKeys: function(value){
        return this.__map.get(value);
    }
};