为什么Array.indexOf找不到相同的外观对象

时间:2012-09-26 14:31:33

标签: javascript arrays search object indexof

我有对象的数组。

像这样:

var arr = new Array(
  {x:1, y:2},
  {x:3, y:4}
);

当我尝试:

arr.indexOf({x:1, y:2});

返回-1

如果我有字符串或数字或其他类型的元素而是对象,那么indexOf()可以正常工作。

有谁知道为什么以及如何搜索数组中的对象元素?

当然,我指的是除了为对象创建字符串哈希键并将其赋予数组之外的其他方式......

8 个答案:

答案 0 :(得分:44)

  

indexOf使用严格相等(使用===或三等号运算符使用的相同方法)将searchElement与Array的元素进行比较。

您不能使用===来检查对象的可用性。

正如@RobG指出

  

请注意,根据定义,两个对象永远不会相等,即使它们具有完全相同的属性名称和值。 objectA === objectB当且仅当objectA和objectB引用相同的对象时。

您只需编写自定义indexOf函数来检查对象。

function myIndexOf(o) {    
    for (var i = 0; i < arr.length; i++) {
        if (arr[i].x == o.x && arr[i].y == o.y) {
            return i;
        }
    }
    return -1;
}

DEMO: http://jsfiddle.net/zQtML/

答案 1 :(得分:12)

如上所述,两个对象永远不会相等,但如果它们属于同一个对象,则引用可以相等,因此要使代码按照您的意愿执行:

var a = {x:1, y:2};
var b = {x:3, y:4};
var arr = [a, b];

alert(arr.indexOf(a)); // 0

修改

这是一个更通用的 specialIndexOf 函数。请注意,它期望对象的值是基元,否则它需要更严格。

function specialIndexOf(arr, value) {
  var a;
  for (var i=0, iLen=arr.length; i<iLen; i++) {
    a = arr[i];

    if (a === value) return i;

    if (typeof a == 'object') {
      if (compareObj(arr[i], value)) {
        return i;
      }
    } else {
      // deal with other types
    }
  }
  return -1;

  // Extremely simple function, expects the values of all 
  // enumerable properties of both objects to be primitives.
  function compareObj(o1, o2, cease) {
    var p;

    if (typeof o1 == 'object' && typeof o2 == 'object') {

      for (p in o1) {
        if (o1[p] != o2[p]) return false; 
      }

      if (cease !== true) {
        compareObj(o2, o1, true);
      }

      return true;
    }
  }
}

var a = new String('fred');
var b = new String('fred');

var arr = [0,1,a];

alert(specialIndexOf(arr, b)); // 2

答案 2 :(得分:10)

这没有自定义代码

var arr, a, found;
arr = [{x: 1, y: 2}];
a = {x: 1, y: 2};
found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
// found === true
  

注意:这不会给出实际索引,它只会告诉您的对象是否存在于当前数据结构中

答案 3 :(得分:3)

这些对象不相等。

您必须实现自己的功能。

您可以这样做:

var index = -1;
arr.forEach(function(v, i) {
   if (this.x==v.x && this.y==v.y) index=i;
}, searched); 

其中searched是您的对象之一(或不是)。

(我会用一个简单的循环来实现它,但它与foreach相比更漂亮)

答案 4 :(得分:2)

因为两个单独的对象彼此不是===,而indexOf使用===。 (他们彼此也不是==。)

示例:

var a = {x:1, y:2};
var b = {x:1, y:2};
console.log(a === b);

=====测试他们的操作数是否引用相同的对象,而不是它们引用等效的对象(具有该对象的对象)相同的原型和属性)。

答案 5 :(得分:1)

由于没有人提到内置函数Array.prototype.findIndex(),所以我想提一下它确实满足作者的需求。

  

findIndex()方法返回元素中第一个元素的索引   满足提供的测试功能的数组。否则-1为   返回。

var array1 = [5, 12, 8, 130, 44];

function findFirstLargeNumber(element) {
  return element > 13;
}

console.log(array1.findIndex(findFirstLargeNumber));
// expected output: 3

在您的情况下,它将是:

arr.findIndex(function(element) {
 return element.x == 1 && element.y == 2;
});

或使用ES6

arr.findIndex( element => element.x == 1 && element.y == 2 );

有关以上示例的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

答案 6 :(得分:0)

这是另一种解决方案,您可以将比较函数作为参数传递:

function indexOf(array, val, from, compare) {

  if (!compare) {
    if (from instanceof Function) {
      compare = from;
      from = 0;
    }
    else return array.__origIndexOf(val, from);
  }

  if (!from) from = 0;

  for (var i=from ; i < array.length ; i++) {
    if (compare(array[i], val))
      return i;
  }
  return -1;
}

// Save original indexOf to keep the original behaviour
Array.prototype.__origIndexOf = Array.prototype.indexOf;

// Redefine the Array.indexOf to support a compare function.
Array.prototype.indexOf = function(val, from, compare) {
  return indexOf(this, val, from, compare);
}

然后您可以这样使用它:

indexOf(arr, {x:1, y:2}, function (a,b) {
 return a.x == b.x && a.y == b.y;
});

arr.indexOf({x:1, y:2}, function (a,b) {
 return a.x == b.x && a.y == b.y;
});

arr.indexOf({x:1, y:2}, 1, function (a,b) {
 return a.x == b.x && a.y == b.y;
});

好处是,如果没有传递比较函数,它仍会调用原始的indexOf。

[1,2,3,4].indexOf(3);

答案 7 :(得分:0)

看起来你对这类答案并不感兴趣,但对于其他感兴趣的人来说这是最简单的:

var arr = new Array(
    {x:1, y:2},
    {x:3, y:4}
);

arr.map(function(obj) {
    return objStr(obj);
}).indexOf(objStr({x:1, y:2}));

function objStr(obj) {
    return "(" + obj.x + ", " + obj.y + ")"
}