Search code examples
javascriptarraysjavascript-objectssplice

Why does splice and/or findIndex not allow a change to the first element of an array/index 0?


My goal here is create a function that will take a text value, loop through an array of objects, and delete the matching element. However, I'm finding that this code does not remove the element if it is the first instance (index 0) and in the instance that it does, only removes the first matching value not any others.

const cats = [{
    name: `catOne`,
    color: `orange`
}, {
    name: `catTwo`,
    color: `Grey-white`
}, {
    name: `catThree`,
    color: `Grey-white`
}] 

const deleteColor = function (arrayOfObjects, clr){

    const index = arrayOfObjects.findIndex(function(e, i){

              if (e.color.toLowerCase() === clr.toLowerCase()){   
                return i;   
              } 
          })
          if (index >= -1 ){ 
          arrayOfObjects.splice(index,1)  
          }
  }

deleteColor(cats,'grey-white')

cats.forEach(function(e, i) {
   console.log(e, i) })

Output:

{ name: 'catOne', color: 'orange' } 0
{ name: 'catThree', color: 'Grey-white' } 1

But if I change the text value input to 'orange', the output is:

{ name: 'catOne', color: 'orange' } 0
{ name: 'catTwo', color: 'Grey-white' } 1
{ name: 'catThree', color: 'Grey-white' } 2

If I change if (index >= -1 ) the output is the same as entering 'grey-white' as the text value.

Can anyone explain why the first element is not removed even though it is index 0? and why index -1 results in removing index 1?

I tried searching around for this but could not find what I was looking for. I've only just started learning vanilla JS. Thanks for your help.


Solution

  • The way the method .findIndex() works is by returning the first index which the callback function returns a truthy value for. In other words, your function should return true or false whenever it is called, not the index at which it appears. When true is returned from your function, .findIndex() will result in the index of the item you returned true for. In your case, your callback function implicitly returns undefined (which is a fasly value) or the index at which the object appears. In the case of "orange", this object appears at index 0, and so you return 0. Zero is considered a falsy value, and so findIndex will continue its search. If it doesn't find any values it will return -1 (which is what's happening when "orange" is entered, so .splice(-1, 1) will remove the last element in the array).

    const cats = [{
      name: `catOne`,
      color: `orange`
    }, {
      name: `catTwo`,
      color: `Grey-white`
    }, {
      name: `catThree`,
      color: `Grey-white`
    }]
    
    const deleteColor = function(arrayOfObjects, clr) {
      const index = arrayOfObjects.findIndex(function(e, i) {
        return e.color.toLowerCase() === clr.toLowerCase(); 
      });
      
      if (index > -1) { // check object was found (Using > not >=)
        arrayOfObjects.splice(index, 1);
      }
    }
    
    deleteColor(cats, 'orange')
    
    console.log(cats);

    If you want to remove all cats with a given color, you can use .filter(). Each call to the callback function which returns true will keep the object, each call which returns false will remove the object:

    const cats = [{ name: `catOne`, color: `orange` }, { name: `catTwo`, color: `Grey-white` }, { name: `catThree`, color: `Grey-white` }];
    
    const deleteColor = function(arrayOfObjects, clr) {
      return arrayOfObjects.filter(e => e.color.toLowerCase() !== clr.toLowerCase());
    }
    
    console.log(deleteColor(cats, 'grey-white'));