0

I am kind of new to javascript and trying to understand some non trivial - at least so i hope :) things.

my question is general, but i have a specific example which can help me ask my question and help you understand what i mean.

the example:

function updateBookmark(bookmark){
    var index = _.findIndex($scope.bookmarks, function(b){
        return b.id == bookmark.id;
    });
    return index;
}

obviously the findIndex function is declared somewhere (in our case - lodash.js) and it gets two parameters (at least two visible parameters: a data set, and a function)

first question:

in this example, what is b? how does b gets its value? i understand b is each of the data set's objects, but i mean - what is going behind the scenes here so b will be what it is??

second question:

the author chose to pass an anonymous function which equals b.id with bookmark.id,

i understand that he can use bookmark.id where he is using it, but how does findIndex has access to this bookmark?!

this function as i concluded earlier is declared somewhere else, does it get all the variables in the scope some how? what is going on here?

Thanks in advance to responders and sorry for the messy question... Jim.

JimmyBoy
  • 351
  • 4
  • 14

1 Answers1

1

If you rewrite some things, it becomes easier to understand.

Starting with the last portion:

// Q: "How does `findIndex`have access to `bookmark`"
_.findIndex(bookmarks, function (b) { });
// A: "It doesn't."
var bookmark = { id: 1 };
var bookmarks = [ /* ... */ ];
function compareWithBookmark( test ) {
  return test.id === bookmark.id;
}
_.findIndex(bookmarks, compareWithBookmark);

As you can see, findIndex doesn't actually have any access to bookmark.
Rather, it has access to a function which it can pass a value to test, and that function will return whether that test passed or failed.

Under the covers of .findIndex or [].map or [].filter, they're all just taking a function, making a loop, passing each element into the function one at a time, and doing something with the return value.

function findIndex (array, test) {
  var index = -1;
  var i = 0;
  var l = array.length;
  var el;
  var result;

  for (; i < l; i += 1) {
    el = array[i];       // <-- how `b` got its value
    result = test(el, i, array); // <-- test(b)
    if (!!result) {
      index = i;
      break;
    }
  }

  return index;
}

The different functions would do different things with the results (map returns a new array which contains each result, filter returns an array where only !!result tests passed, et cetera), but all of them do this inner-looping.

This is also a pretty gross simplification of the looping structure and considerations, but it's exactly what's driving your expected behaviour.

Edit

Here is a full usage of the function I just defined, plus the array, plus the object I'm checking.

var bookmarks = [
  { id:  2 },
  { id:  3 },
  { id:  6 },
  { id: 14 }
];

var bookmark = { id: 3 };
function compareBookmarkIdTest (el) {
  return el.id === bookmark.id;
}

var index = findIndex(bookmarks, compareBookmarkIdTest);
index; // 1

Hope that helps.

Norguard
  • 26,167
  • 5
  • 41
  • 49
  • Thanks, that helps much more than voting my question down and leaving :) the function in my example does: return b.id == bookmark.id; so when findIndex uses it - it equals b.id with the number evaluated from bookmark.id? for example, it replaces the bookmark.id to 5? are the two exclamation marks (!!) on purpose? if so - what do they mean? can you also explain how the b argument got its value? sorry for harassing you :-/ – JimmyBoy Jun 09 '15 at 15:37
  • 1
    Have a look at my edits. I've written not only a version of findIndex, but also written how it would be used in a very simple example. Track through the flow of that little program. You'll see exactly where the value of `b` comes from. `!result` is "not `result`" `!!result` is "not not result". The difference is that `!result` is always Boolean, `result` could be anything... ...so `!!result` is guaranteed to be Boolean, too. Don't worry about it, in 95% of the cases that matter `if (result)` and `if (!!result)` do the same thing. – Norguard Jun 09 '15 at 17:06