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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12604062/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 10:48:13  来源:igfitidea点击:

Why Array.indexOf doesn't find identical looking objects

javascriptarrayssearchobjectindexof

提问by Jibla

I have array with objects.

我有对象的数组。

Something Like this:

像这样的东西:

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

When I try:

当我尝试:

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

It returns -1.

它返回-1

If I have strings or numbers or other type of elements but object, then indexOf()works fine.

如果我有字符串或数字或其他类型的元素但对象,则indexOf()工作正常。

Does anyone know why and what should I do to search object elements in array?

有谁知道为什么以及我应该怎么做来搜索数组中的对象元素?

Of course, I mean the ways except making string hash keys for objects and give it to array...

当然,我的意思是除了为对象制作字符串哈希键并将其赋予数组之外的方法......

回答by Selvakumar Arumugam

indexOf compares searchElement to elements of the Array using strict equality (the same method used by the ===, or triple-equals, operator).

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

You cannot use ===to check the equability of an object.

您不能用于===检查对象的平等性。

As @RobGpointed out

正如@RobG指出的那样

Note that by definition, two objects are never equal, even if they have exactly the same property names and values. objectA === objectBif and only if objectA and objectB reference the same object.

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

You can simply write a custom indexOf function to check the object.

您可以简单地编写一个自定义的 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/

演示:http : //jsfiddle.net/zQtML/

回答by RobG

As noted, two objects are never equal, but references can be equal if they are to the same object, so to make the code do what you want:

如前所述,两个对象永远不会相等,但如果它们指向同一个对象,则引用可以相等,因此要使代码执行您想要的操作:

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

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

Edit

编辑

Here's a more general specialIndexOffunction. Note that it expects the values of the objects to be primitives, otherwise it needs to be more rigorous.

这是一个更通用的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

回答by Xeltor

This works without custom code

这无需自定义代码即可工作

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

Note: this does not give the actual index, it only tells if your object exists in the current data structure

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

回答by Matt

As nobody has mentioned built-in function Array.prototype.findIndex(), I'd like to mention that it does exactly what author needs.

由于没有人提到内置函数 Array.prototype.findIndex(),我想提一下它正是作者所需要的。

The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.

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

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

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

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

In your case it would be:

在您的情况下,它将是:

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

Or using ES6

或者使用 ES6

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

More information with the example above: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

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

回答by Denys Séguret

Those objects aren't equal.

这些对象不相等。

You must implement your own function.

您必须实现自己的功能。

You may do that for example :

你可以这样做,例如:

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

where searchedis one of your object (or not).

searched你的对象之一在哪里(或不是)。

(I would implement it with a simple loop but it's prettier with foreach)

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

回答by T.J. Crowder

Because two separate objects are not ===to each other, and indexOfuses ===. (They're also not ==to each other.)

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

Example:

例子:

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

===and ==test for whether their operands refer to the same object, not if they refer to equivalentobjects (objects with the same prototype and properties).

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

回答by Dal

Looks like you weren't interested in this type of answer, but it is the simplest to make for others who are interested:

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

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 + ")"
}

回答by Kristian Benoit

Here's another solution, where you pass a compare function as a parameter :

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

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);
}

You can then use it these way:

然后,您可以通过以下方式使用它:

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;
});

The good thing is this still calls the original indexOf if no compare function is passed.

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

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