0

This piece of code comes from a freeCodeCamp challenge. And it works. But I need some clarification. In the exercise, it is about reading a json array to extract the value of the given firstName property when calling the lookUp function. Also, check such property exists before reading its value.

When contacts.some declares the callback function (arg) {...}, it seems that 'arg' already knows the 'firstName' and 'prop' parameters passed when calling the lookUp function.

//Setup
var contacts = [
    {
        "firstName": "Akira",
        "lastName": "Laine",
        "number": "0543236543",
        "likes": ["Pizza", "Coding", "Brownie Points"]
    },
    {
        "firstName": "Harry",
        "lastName": "Potter",
        "number": "0994372684",
        "likes": ["Hogwarts", "Magic", "Hagrid"]
    },
    {
        "firstName": "Sherlock",
        "lastName": "Holmes",
        "number": "0487345643",
        "likes": ["Intriguing Cases", "Violin"]
    },
    {
        "firstName": "Kristian",
        "lastName": "Vos",
        "number": "unknown",
        "likes": ["Javascript", "Gaming", "Foxes"]
    }
];

function lookUp(firstName, prop) {
  // Only change code below this line
  var answer = "No such contact";
  contacts.some(function(arg) {
    if (arg.firstName === firstName && arg.hasOwnProperty(prop) === true) {
      answer = arg[prop];
    } else if (arg.hasOwnProperty(prop) === false) {
      answer = "No such property";
    }
  });
  return answer;
  // Only change code above this line
}

// Change these values to test your function
lookUp("Kristian", "lastName");

I do not understand where the magic is. Why does 'arg' contain the value of both parameters? Could anyone explain how this happens?

Thanks in advance. Carlos.

cga
  • 5
  • 2
  • 2
    *"...it is about reading a json array"* No, it's about reading an array. No JSON involved. JSON is a *textual notation* for data exchange. [(More)](http://stackoverflow.com/a/2904181/157247) If you're dealing with JavaScript source code, and not dealing with a *string*, you're not dealing with JSON. – T.J. Crowder Jan 26 '17 at 18:45
  • 1
    This is all explained in the documentation for [`some()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) – Ted Hopp Jan 26 '17 at 18:47
  • Note that the code you've found there is quite poor, see my comment on [this answer](http://stackoverflow.com/a/41880800/157247) for a concise version of why (and those are just the things I noted in a quick scan through). – T.J. Crowder Jan 26 '17 at 19:04
  • @TedHopp: True, though it probably doesn't help that the code is misusing `some` and relying on closures. – T.J. Crowder Jan 26 '17 at 19:04

1 Answers1

3

The function as written contains logic errors which will prevent it from doing what it is designed to do. However, I am going to address specifically your question about how the callback can see the lookUp function's parameters and properties in array items.

In JavaScript, functions defined within a given scope can see the variables from the scope they're in. So, for instance:

var variable = 5;

function incrementVariable()
{
  variable++;
}

In this sample, incrementVariable can see the variable variable even though it is defined outside of the function. In this sample, variable is global, but this could be done inside of another function:

function doSomething()
{
  var variable = 5;

  function incrementVariable()
  {
    variable++;
  }

  ...
  incrementVariable();
  ...
}

Parameters to a function are just another type of variable, so for instance:

function doSomething(variable)
{
  function incrementVariable()
  {
    variable++;
  }

  ...
  incrementVariable();
  ...
}

doSomething(5);

In the lookUp function you posted, the argument to contacts.some(..) is a function defined within the lookUp function, so it can "see" everything that the lookUp function itself can see, including its parameters.

The technical term for this type of shared scope is a "closure".

The arg argument to the callback function is defined by what the some() function itself is doing. The callback gets called once for each of the elements in the contacts array. So, for instance, the first call back has this in arg:

{
    "firstName": "Akira",
    "lastName": "Laine",
    "number": "0543236543",
    "likes": ["Pizza", "Coding", "Brownie Points"]
}

Thus, the callback can see both firstName, the argument to lookUp, and arg.firstName, which in this case is the string "Akira". Similarly, if prop is, say, "number", then arg[prop] refers to the "number" property in that object, which in this case will be "0543236543".

Jonathan Gilbert
  • 3,526
  • 20
  • 28
  • Probably worth mentioning that the code is misusing `some`, has a completely pointless `=== true` comparison, calls `hasOwnProperty` repeatedly rather than just once, and gives the wrong result if there's a matching contact at, say, index 1 but an object later at, say, index 3 which doesn't have the `firstName` property. – T.J. Crowder Jan 26 '17 at 19:03
  • These things are all true, but are separate issues from the question of how the callback can see the arguments to `lookUp` and properties of the objects in the array. :-) – Jonathan Gilbert Jan 26 '17 at 19:12
  • If that's the question (I'm still not entirely sure what the question actually is), but frankly a couple of those really should be noted in *any* answer to this question. – T.J. Crowder Jan 26 '17 at 19:27