13

UPDATE: Although this question is marked as duplicated with this. But @ssube's way is neat and much smarter.

UPDATE2: Seems there is new way to do it in the comment by @Grungondola.

I am using Typescript.

This works well.

var array1 = [];
array1.push(5);
array1.push(6);
console.log("a", array2.indexOf(6));

But this does not work well. Because array2.indexOf returns -1 which means it does not find it.

var array2 = [];
array2.push({aa:5,bb:5});
array2.push({aa:6,bb:6});
console.log(array2.indexOf({aa:6,bb:6}));

Looks like indexOf does not support Object. Does TypeScript have its own ways to deal with this kind of problem? Thanks.

Hongbo Miao
  • 45,290
  • 60
  • 174
  • 267
  • This really has nothing to do with TypeScript. In JavaScript two objects are never `equal`. You'll have to write a custom search. – Dave Feb 04 '16 at 17:05
  • `indexOf()` is a method for objects of type String, not Array – Marcos Pérez Gude Feb 04 '16 at 17:05
  • Sorry, I'm mistaken. There are an `indexOf()` for arrays : https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/indexOf . Thousands of sorrys :( – Marcos Pérez Gude Feb 04 '16 at 17:06
  • 2
    As of es2015, there is a function on arrays called `findIndex` that accepts a predicate in the same way as `find` and would allow you to do a deep search for the object that you want. I would provide this as an answer, but answering is not possible any more. The problem with this is that it lacks support in IE for some reason, but there is a polyfill that you can add for that: [findIndex Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) – Grungondola Oct 31 '18 at 12:13
  • If the purpose is just to know if an element exists refer to array.some – João Rodrigues Dec 07 '18 at 16:20

1 Answers1

28

No. The problem is not with Object, but that you are creating two different objects.

The object literal syntax ({foo: 'bar'}) declares an object inline. When the script is executed, the object is created. Using that syntax multiple times creates multiple objects.

You can easily test that with {foo: 3} === {foo: 3}. This will evaluate to false, but they are not the same object (reference).

The indexOf method checks if the object, string, number, etc, is present in the array. You're passing a new object, which is not in the array.

If you have a reference to the object, you can use that and indexOf will work:

var foo = {aa:5,bb:5}, bar = {aa:6,bb:6};
var array2 = [];
array2.push(foo);
array2.push(bar);
console.log(array2.indexOf(foo));

Because you're referring to the same instance, this will print the index.

You can also use filter or find with a predicate to perform a deep search:

function deepIndexOf(arr, obj) {
  return arr.findIndex(function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

var array2 = [];
array2.push(foo);
array2.push(bar);
console.log(deepIndexOf(array2, foo));

This won't recurse into nested objects, but will accomplish the comparison you're looking for (equivalence on two objects and their immediate fields).

ssube
  • 47,010
  • 7
  • 103
  • 140
  • Premature optimization et cetera, but this could be optimized. At least, getting the `keys` and `values` from `arr` before the loop... And where are those nice arrow functions? They could maximize the simplicity to its half ;) – yckart Feb 19 '16 at 14:30