Skip to content

Instantly share code, notes, and snippets.

@GeekTrainer
Last active February 14, 2021 14:24
Show Gist options
  • Save GeekTrainer/5505c6bd781f7fb0e094507dafe0976a to your computer and use it in GitHub Desktop.
Save GeekTrainer/5505c6bd781f7fb0e094507dafe0976a to your computer and use it in GitHub Desktop.
Delegates in JavaScript

Delegates in JavaScript

One of the more confusing aspects of programming in 2018 is managing long running operations. These are typically operations that access an external system, such as a database or REST API. We don't want our code to wait if it's unnecessary, and our users certainly don't want that either. Figuring out how to let our application know it's able to do other things, while still ensuring our code is called in response to the operation, requires a little bit of coordination and work.

What I want to do with this gist, and three others, is walk through the syntax systematically, showing the evolution of Node/JavaScript/ECMAScript. Hopefully this will help solidify understanding of these key concepts.

Let's start off by taking a look at delegates, which will set the stage for the rest of the concepts.

Delegates

Let's start with an array of JSON objects.

let people = [
  { first: 'Christopher', last: 'Harrison' },
  { first: 'Susan', last: 'Ibach' },
  { first: 'Graeme', last: 'Malcolm' },
];

Now let's say I want to find Graeme in this list and print his last name on the screen. One way we could do this would be by creating a for loop. (I'm just going to use a classic for loop)

// assuming above code
for(let index = 0; index < people.length; index++) {
  if(people[index].first === 'Graeme') {
    console.log(`Found ${people[index].last}`);
    break;
  }
}

While the code certainly works, it's not the most elegant. It'd be nice to be able to call a function called find (which does exist, and I'll get to in just a moment), and provide our critera of the first name being Graeme. Let's focus on the key part of the filtering we're doing, which is people[index].first === 'Graeme'. Let's break this down into its components.

  1. Grab the current person in the loop by calling people[index]
  2. Retrieve the first property
  3. See if first is equal to Graeme
  4. The operation returns a boolean value

If we step back and take a look at this from a higher level, we can see we're defining a search algorithm. We're working through each item, performing some comparison, and returning a boolean value. We could potentially redefine our search to look like the following, which could make things a bit more readable.

function isGraeme(person) {
  return person.first === 'Graeme';
}

for(let index = 0; index < people.length; index++) {
  if(isGraeme(people[index])) {
    console.log(`Found ${people[index].last}`);
    break;
  }
}

We're now doing the same thing as before, but we've taken the key part of the algorithm - the comparison - and moved it into a helper function. While we've bought a little bit of readability, we still have a fair bit of code. It'd be nice to simplify the code even further, removing the need for the for loop.

Enter find. find encapsulates the entire for statement for us. It will walk through every item automatically, perform the comparison we give it (which we'll see in a moment), and return the first item that matches. You could basically think of find as the following code:

// Exists inside of the array definition
// The code that is actually in existance may well be different;
// this is for demonstration purposes only
Array.prototype.find = function (comparison) {
  // this is the current array
  for(let index = 0; index < this.length; index++) {
    // run the comparison function passed in
    if(comparison(this[index])) {
      // true, so return the current item
      return this[index];
    }
  }
  // no match found; return null
  return null;
}

You'll notice the above code is very similar to the reworked loop we created. The main difference is unlike creating a specific method like we did (isGraeme in our case), they are accepting a parameter called comparison, expecting that to point to a function. We can take advantage of this by creating the following code:

function isGraeme(person) {
  return person.first === 'Graeme';
}

let graeme = people.find(isGraeme);
if(graeme) console.log(`Found ${graeme.last}`);
else console.log(`No entries found`);

We're basically doing the same thing as before, only this time we're letting find do the looping and finding for us.

But... You'll notice that we're having to still create a function. That could get rather messy if we're trying to do lots of searching. Let's way we wanted to find Susan or Christopher. Do I have to create yet another function? Fortunately, the answer is no.

If we take a look at isGraeme, what we'll notice is it's taking in the current item (a person in our case), and performing a boolean operation, and returning the result. Rather than creating a full function to do that, why not just do it inline? Fortunately, we can!!

// Create the function inline!
let graeme = people.find(function(person) {
  return person.first === 'Graeme';
});
if(graeme) console.log(`Found ${graeme.last}`);
else console.log(`No entries found`);

Much cleaner!! But... It's still a bit verbose. I mean, do we really need to type out the word function? Fortunately, we don't! There's a special syntax for creating functions called a "fat arrow" function. There are certain additional benefits to using a fat arrow function, but the main one is readibility. It's also less typing, which is always a bonus.

// Same as before!!!
let graeme = people.find((person) => {
  return person.first === 'Graeme';
});
if(graeme) console.log(`Found ${graeme.last}`);
else console.log(`No entries found`);

But... You know... The function we created there is going to return a boolean. Why do we have to type out the return statement? Well - we don't. :-) We can create what's known as a lambda statement where we leave off the curly braces {}. By doing so, the result of the expression is automatically returned.

// Same as before!!!
// Not the lack of {} after the =>
// Also note the lack of () surrounding the person parameter
let graeme = people.find(person => person.first === 'Graeme');
if(graeme) console.log(`Found ${graeme.last}`);
else console.log(`No entries found`);

In the end, we've taken what was about 6 lines of code and whittled it down to 3 powerful, easy to read and digest, lines of code. This is the foundation for moving forward into callbacks, which we'll take a look at in the next writeup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment