This is part two of the series javascript simplified. This entry covers the callbacks, anonymous functions, and ES6 arrow functions, otherwise known as fat arrow notation.
A callback is a function that is passed into another function as an argument that typically is executed at a later time. The most popular use of a callback javascript is most likely the setTimeout function. This function has two arguments. The first is the function to call, and the second is how many milliseconds to wait before calling.
function sayHello() {
console.log('Hello');
}
setTimeout(sayHello, 1000); //outputs Hello after 1000 milliseconds (1 second)
It is possible to consolidate this code a bit by introducing an anonymous function. Simply put, an anonymous function is a function without a name.
We could write the code above as follows.
var sayHello = function () {
console.log('Hello');
};
setTimeout(sayHello, 1000); //outputs Hello after 1000 milliseconds (1 second)
That example assigns an anonymous function to the sayHello variable. There are many cases where a name is unneeded. For example, our code has no need to assign the name sayHello.
setTimeout(function () {
console.log('Hello');
}, 1000); //outputs Hello after 1000 milliseconds (1 second)
ES6 / ECMAScript 2015 has introduced an even more concise way of defining anonymous functions in what is commonly referred to as Fat Arrow Functions. Take a look at the change to the code using this new syntax.
setTimeout(() => {
console.log('Hello');
}, 1000); //outputs Hello after 1000 milliseconds (1 second)
We can simply replace the function() with a () =>. The equals and the greater than sign looks like a large arrow, thus the name fat arrow.
This syntax has an additional advantage as it solves one of the issues plaguing javascript developers for years. To explain, I will extend the example from the previous article with the Person object.
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return this.firstName + ' ' + this.lastName;
}
sayHello() {
setTimeout(function() {
console.log('Hello, my name is ' + this.fullName);
}, 1000);
}
}
var p = new Person('Bilbo', 'Baggins');
p.sayHello(); //after 1 second outputs Hello, my name is undefined
Notice the output did not work correctly. The reason is the this
object does not hold a reference to our Person instance. Instead it holds a reference to the owner of the function it is in, for web developement this would be the window object. To get around the issue, developers typically would define a variable to hold onto what this
is prior to executing the code that is given the callback function.
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return this.firstName + ' ' + this.lastName;
}
sayHello() {
var self = this; //hold onto our object reference to use below
setTimeout(function() {
console.log('Hello, my name is ' + self.fullName); //use the self variable to get access to our object instance
}, 1000);
}
}
var p = new Person('Bilbo', 'Baggins');
p.sayHello(); //after 1 second outputs Hello, my name is Bilbo Baggins
As you can imagine, having the keyword this
refer to different things within your classes can be quite problematic. Thankfully, help is on the way when you use fat arrows, as they will maintain your this context for you.
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return this.firstName + ' ' + this.lastName;
}
sayHello() {
setTimeout(() => { //fat arrow here means our this context will remain intact
console.log('Hello, my name is ' + this.fullName); //we can now use this thanks to our =>
}, 1000);
}
}
var p = new Person('Bilbo', 'Baggins');
p.sayHello(); //after 1 second outputs Hello, my name is Bilbo Baggins
Hopefully this entry was helpful to you. Check back later for more articles in this series 😉.