2

Im trying to get indexOf of a object after its pushed inside a array. This is not returning the same value back as i do indexOf whenever objext is allready in the array.

SCENARIO


var arr = [];
setInterval(function() {
 var path = { one: "f00"};
    if (typeof path !== "undefined") {
        if (arr.indexOf(path) === -1) {
            console.log("Not Exists!!")
            arr.push(path)
        } else {
            console.log("Exists!!")
        }
    }
 console.log(arr)
}, 2000)

What is the different between the working of

John Smiths
  • 119
  • 9
  • 1
    You're using an object in the indexOf, it might not know how to compare them – Patrick Barr Mar 13 '17 at 16:51
  • @PatrickBarr but the first one it shows the correct status – John Smiths Mar 13 '17 at 16:51
  • `arr` doesn't contain the literal object defined in the argument for `indexOf`. – Teemu Mar 13 '17 at 16:51
  • 2
    @JohnSmiths because you're passing a direct reference to the object instead of another object that has the same data – Patrick Barr Mar 13 '17 at 16:52
  • 2
    Possible duplicate of [Javascript oddness with array of objects and indexOf](http://stackoverflow.com/questions/8618200/javascript-oddness-with-array-of-objects-and-indexof) – Heretic Monkey Mar 13 '17 at 16:53
  • 1
    @MikeMcCaughan no its not, the first console.log returns correct value "0" and the second console shows -1 – John Smiths Mar 13 '17 at 16:54
  • 1
    Possible duplicate of [Javascript array.indexOf doesn't search objects](http://stackoverflow.com/questions/12604062/javascript-array-indexof-doesnt-search-objects) – Sebastian Simon Mar 13 '17 at 16:54
  • 1
    @Xufox, no its not, the first console.log returns correct value "0" and the second console shows -1 ... – John Smiths Mar 13 '17 at 16:55
  • 1
    @JohnSmiths This _is_ a duplicate of those questions because they both have the same fundamental problem as your question. It doesn’t matter whether you additionally did something else correctly; it only matters whether it’s the _same mistake_ that you did. And you did exactly that. Also, you clearly haven’t read all of the answers there. They actually do answer why something like `.indexOf(path)` works. – Sebastian Simon Mar 13 '17 at 16:57
  • because in the first case you pass `path` which contains the reference of the object you're looking for, try to execute in console `{ path: "foo"} === { path: "foo"}`, the output will be false because you're comparing 2 different objects (even if they have the same content) – Sabaz Mar 13 '17 at 16:57

2 Answers2

1

The issue is that JavaScript doesn't do a deep compare of objects, so it doesn't recognize them as the same.

var a = { name: 'foo' }
var b = { name: 'foo' }
a === b // false

However, since you have access to the object before the insert, you can save a reference to it, and then search for that reference:

var arr = []
var obj = { path: 'foo' }
arr.push(obj)
arr.indexOf(obj) // 0

This is because indexOf uses the strict equality === comparison. So in this case, the references to obj and the object at arr[0] are the same.

Edit

Based on your changed question, here is a way to write your function to do what you want:

var arr = [];

function findAdnSet(obj) {
  var index = arr.indexOf(obj);

  if (index !== -1) {
    return index;
  } else {
    arr.push(obj);
    return arr.length - 1; // No reason to use indexOf here, you know the location since you pushed it, meaning it HAS to be the last element in the array
  }
}

var path = { name: 'foo' };
findAndSet(path);

A more robust option than using indexOf since your function might not always have a good reference available is to use find/findIndex:

var arr = [];

function findAndSet(obj) {
  var index = arr.findIndex(function(item) {
    if (item.name === 'foo') {
      return true;
    }
  });

  if (index) { // findIndex returns `undefined` if nothing is found, not -1
    return index;
  } else {
    arr.push(obj);
    return arr.length - 1;
  }
}

// You don't need a reference anymore since our method is doing a "deep" compare of the objects
findAndSet({ name: 'foo' });
Matthew Herbst
  • 29,477
  • 23
  • 85
  • 128
  • I edited my code, can you show example with that one. Why i dont get ! -1 – John Smiths Mar 13 '17 at 17:12
  • The reference to `path` changes each time the function is run, since you redefine `path` each time the function is run. You'll have to save `path` before you define the `setTimeout` call. – Matthew Herbst Mar 13 '17 at 17:20
  • Is it because i'm using setInterval and forEach() to get the path ? – John Smiths Mar 13 '17 at 17:32
  • Well, I don't see a `forEach` anywhere in your code, but yes to the `setInterval`. Every time you call the function everything inside is happening for essentially the *first* time. When the function ends in-between runs the internal scope (memory) of the function is lost. – Matthew Herbst Mar 13 '17 at 18:04
  • I have added two new examples that should help you. – Matthew Herbst Mar 13 '17 at 18:12
0

The first time you do indexOf you push and search for the object 'path' so it is found. The second time you create an object and add push it to the array, and then search for another new object (which happens to have the same values), but since it is not the same object that you pushed it is not found.

user7491506
  • 186
  • 1
  • 3