Trying to grasp callback functions

So I’m trying to recreate a simple age calculator that’s part of my classwork, it’s my way of trying to cement some of the things that I have learned.

My code isn’t working and is returning null. I’ll keep looking into that, but I am all ears.

What I’m really struggling with is the argument (or variable?) el. I can see where information is passed through the arr and fn arguments of the arrayCalc function, but I am completely lost as to how the el argument interacts with the
years variable at all.

Here’s a link to the project https://scrimba.com/c/cBzMgvTy

Hi @CooKachoo, just a small mistake – you’re not calculating the ages from the input array but from the (empty) results array; and accessing an index the array does not have will give you undefined, and 2020 - undefined again NaN (not a number). That this scrimba platform prints null here is actually wrong, if you run the code from the console you’ll get [NaN, NaN, NaN, ...].

The el argument is the current element of the years array over which the for loop iterates… interacting is maybe the wrong word though, it’s just the elements that the array contains.

1 Like

S’also worth pointing out that CurrentYear-YOB != Age. :wink: (S’only true if your birthday has already occured this year. My birthday is in November, so this function is almost always wrong for me!)

Maybe some coloration of the class’ code would make it a bit more obvious, because those variable/parameter names are doing my head in, and I know what i’m doing.

function arrayCalc(arr, fn) {
    var arrRes = []; 
    for (var c = 0; c < arr.length; c++) {
        arrRes.push(fn(arr[c]));  
    }
    return arrRes;
}

function calculateAge(el) {
    return 2020 - el; 
}

var ages = arrayCalc(years, calculateAge);

Everything that is the same color is a reference to that thing. (yes, the parameter of fn should also be blue. But the green was more important there.)

Ooh, this could be a challenge, of how to rework the code so that it’s easier to understand.

First in arrayCalc, we can use a temporary variable for each array item, which makes it easier to step to forEach later on.

function arrayCalc(arr, fn) {
    var arrRes = []; 
    for (var c = 0; c < arr.length; c++) {
       var item = arr[c];
        arrRes.push(fn(item));
    }
    return arrRes;
}

we can now easily use forEach instead of the for loop.

function arrayCalc(arr, fn) {
    var arrRes = []; 
    // for (var c = 0; c < arr.length; c++) {
    //    var item = arr[c];
    arr.forEach(function (item) {
        arrRes.push(fn(item));
    });
    // }
    return arrRes;
}

And we can avoid making changes to a variable external to the forEach loop, by using map instead to build up the array.

function arrayCalc(arr, fn) {
    var arrRes = arr.map(function (item) {
        return fn(item);
    });
    return arrRes;
}

And we are no longer doing anything with arrRes, so we can just return the map.

function arrayCalc(arr, fn) {
    // var arrRes = arr.map(function (item) {
    return arr.map(function (item) {
        return fn(item);
    });
    // return arrRes;
}

And instead of the function that we use with the map method, we can just use the fn function itself.

function arrayCalc(arr, fn) {
    return arr.map(fn);
}

And we could even remove the arrayCalc function completely by moving that map method down to the ages calculation.

// function arrayCalc(arr, fn) {
//     return arr.map(fn);
// }
function calculateAge(el) {
    return 2020 - el; 
}

// var ages = arrayCalc(years, calculateAge);
var ages = years.map(calculateAge);

And instead of that calculateAge function, we could use arrow-notation instead:

// function calculateAge(el) {
//     return 2020 - el; 
// }
var calculateAge = (el) => 2020 - el;
var ages = years.map(calculateAge);

And we can rename that misleading el variable so that it’s more meaningfully named:

var calculateAge = (year) => 2020 - year;
var ages = years.map(calculateAge);

And we can even move that arrow-notation into the map method:

// var calculateAge = (year) => 2020 - year;
// var ages = years.map(calculateAge);
var ages = years.map(year => 2020 - year);

Summary

The code started off as the following code:

function arrayCalc(arr, fn) {
    var arrRes = []; 
    for (var c = 0; c < arr.length; c++) {
        arrRes.push(fn(arr[c]));  
    }
    return arrRes;
}

function calculateAge(el) {
    return 2020 - el; 
}

var ages = arrayCalc(years, calculateAge);

And has been gradually improved to this much simpler single line of code:

var ages = years.map(year => 2020 - year);

Is that single line instead of 11 an improvement? I think so.

1 Like

I had a look at this earlier and was reticent about posting. Likewise the names were bothering me. For instance ‘el’ or ‘elem’ in my mind is more appropriate for a DOM element, than an item in an array of years.

I just went for more descriptive names instead.

var birthYears = [1192, 1998, 1984, 1979, 2000, 2005, 2008]

function getAges (years, calculateAgeFn) {
  var ages = []

  for (var i = 0, len = years.length; i < len; i++) {
    ages.push(calculateAgeFn(years[i]))
  }
  return ages
}

function calculateAge (birthYear) { // no need for comment — excuse the irony
  return 2020 - birthYear
}

var ages = getAges(birthYears, calculateAge)
console.log(ages)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.