JavaScript Arrow functions, what are they ?

When i first came across an arrow function, i thought what a cool way to write a function . Oh , and it saves time and space too besides looking like a cool mathematic’s formulae. Until i read and learnt the full idea, reason and what differentiate it from the usual js functions, i literally used it like every other function. Unfortunately , i recently learn’t at work that most of my junior colleagues, still hold similar view . This perception is especially common among the fullstack folks.
There are many articles about arrow functions online, but none seem to put it the way i like it like the mozilla developer documentation on array function here. I like the first opening statement from their article the most, which aimed to clarify the differences between array function and the traditional JavaScript function
An arrow function expression has a shorter syntax than a function expression and does not have its own
this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors. — — Mozilla documentation
In this article, i would like to summarise on the difference between array function and the usual javascript function by elaborating on the summary above with examples.
Below are the main points from the statement.
- Has a shorter syntax than a function expression;
- Doesn’t have it’s own
this. - Doesn’t have its own
arguments. - Doesn’t have its own
super. - Doesn’t have its own
new.target. - And the last but not the least , arrows functions are best suited for non-method functions, and they cannot be used as a constructors.
Has a shorter syntax than than a function expression
This feature is what first grab most peoples attention to arrow functions.That is, Its shorter and more convenient than function expression . What’s a function expression ?
function expression is one way function objects are created in javascript . The other way is function declaration. example below.
function expression
function sumNumbers(a, b) {
return a + b;
}
sumNumbers(2,3); // returns 5;function declaration
const sumNumbers = sumNumbers(a, b) {
return a + b;
}
sumNumbers(2,3); // returns 5;The above two are similar in every way except, function expression declares a function object which can be use before declaration. Example,
console.log(sunNumbers(2,3)); //yield 5.
function sumNumbers(a, b) {
return a + b;
}And function declaration declares a function variable which like every other variable, cannot be used unless its defined . That is,
console.log(sunNumbers(2,3)) //result in error
const sumNumbers = function(a, b) {
return a + b;
}From the above, sumNumbers is used before definition or declaration and like every other variable, it doesn’t exist. An address of its definition location is not available in memory hence the error
Uncaught ReferenceError: sumNumbers is not defined
Coming back to our topic, the two functions above can simply be declared in arrow functions like below.
//function declarationconst sunNumbers = (a, b) => a + b;
Arrow function does not exist as a function expression. Its always part of a bigger object like below below or a variable like above.
const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea:function() {
const area = () => this.height * this.width;
return area();
}
}This is because array-functions doesn’t have or take its own scope during execution , it rather occupy the scope of its surrounding parent . From the object above, this refers to shape object, because the area function being an array function , doesn’t have its execution scope. This lead us to the second difference, before we proceed pls and learn the array function syntax below
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalent to: => { return expression; }
// Parentheses are optional when there's only one parameter name:
(singleParam) => { statements }
singleParam => { statements }
// The parameter list for a function with no parameters should be written with a pair of parentheses.
() => { statements }
More on Syntax or Advanced Syntax
// Parenthesize the body of function to return an object literal expression:
params => ({foo: bar})
// Rest parameters and default parameters are supported
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }
// Destructuring within the parameter list is also supported
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
Doesn’t have it’s own this.
Consider the Object below
const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea:function() {
const area = () => this.height * this.width;
return area();
}
}console.log(shape.getArea()); //result 45 * 40;var newShape = shape;
console.log(newShape.getArea()); //result 45 * 40;var theShape = shape.getArea;
console.log(theShape()); // result NaN
From the above, in the first console, the surrounding scope of getArea is defined by shape and in that very scope, heigh= 45 and width=40 So, this in the first console is referring to shape.
In the second console statement, newShape = shape and therefore newShape.getArea takes the surrounding of newShape which is basically the shape itself hence newShape = shape and height and width in newShape equals the height and width in newShape which are 45 and 40 respectively.
In the third console statement, theShape = shape.getArea . theShape has the definition of getArea not its shape surrounding. Therefore theShape doesn’t have any idea what other properties of shape are. Our new Object theShape has a new surrounding scope or environment and its definitely not the shape’s environment . In this case, theShape’s environment is the global window environment and within the environment , height and width are undefined. Now let’s update our code by giving the surrounding window object environment a height and width.
height = 10;
width= 20;const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea:function() {
const area = () => this.height * this.width;
return area();
}
}console.log(shape.getArea()); //result 45 * 40;var newShape = shape;
console.log(newShape.getArea()); //result 45 * 40;var theShape = shape.getArea;
console.log(theShape()); // result 10 * 20;
Now theShape’s height and width are given a definition and you can see our theShape has changed as well.
Doesn’t have its own arguments.
The
argumentsobject is anArray-like object corresponding to the arguments passed to a function.
Consider the examples below
let sumNumbers = function(a, b) {
return arguments[0] + arguments[1];
}console.log(sumNumbers(2, 3)) // result 5;sumNumbers = (a, b) => {
return arguments[0] + arguments[1];
};console.log(sumNumbers(2, 3)); // undefined
From the above, the first sumNumbers has an argument object(try adding console message to view) containing the parameters.
The second , using array function has no neither this scope/pointer nor argument and just like the case is with this , the arguments object inside arrow function is the arguments of the surrounding object which in this case is window with its events .
Doesn’t have its own super.
The super keyword is used to access and call functions on an object’s parent.
Its simply the javascript way of utilising object inheritance.
class shape {
constructor(type) {
this.type = type;
this.height = 10;
this.width = 20;
}
get shapeType() {
return this.type;
}
set shapeType(type){
this.type = type;
} getArea() {
return this.height * this.width
}}class Rectangle extends shape {
constructor() {
super();
this.type = "rectangle";
}
}var rectangle = new Rectangle();
console.log(rectangle.type); // yield rectangle
console.log(rectangle.getArea()); // result 10 * 20;
Now change getArea() to arrow function and try again .
getArea = () => {
return this.height * this.width
}The above code would not event compile, there would be an error saying
“Class properties must be method”
This is because getArea with array function is a property variable with function type, while getArea , the method which is
getArea() {
return this.height * this.width
}is a method. And ES classes handle methods and properties in entirely different ways. Methods are existed on class prototype, while properties are being assigned to every instance. And you can’t access parent’s getArea with arrow function via super.getArea due to it is not on your parent's class, it is only on instance object and could be accessed via instance.getArea. Since the classes only allow methods as a properties and arrow function is not a method, the stable ES disallowed the adding of non method properties. It throws an error when added. See the question here for similar discussion.
Doesn’t have its own new.target.
This feature as its predecessor, has been added a restrictions by ES compilers. Most of the current javaScript editors would throw an error when these two rules are violated because just like it has been integrated by the modern EcmaScript, editors or compilers understand this. In the absence of a compiler or a proper editor, an error is thrown in the run time. Consider the code below
const sumNumbers = function(a, b) {
if (!new.target) throw 'sumNumbers() must be called with new';
this.value a + b;
}console.log(sumNumbers(3, 2)); sumNumbers() must be called with new;
console.log(new sumNumbers(3, 2)); // result: { value: 5}
Now modify the above and use arrow functions instead.
const sumNumbers = (a, b) => {
if (!new.target) throw 'sumNumbers() must be called with new';
this.value a + b;
}console.log(sumNumbers(3, 2)); TypeError: sumNumbers is not a constructor;console.log(new sumNumbers(3, 2)); //TypeError:sumNumbers is not a constructor
TypeError: sumNumbers is not a constructor
sumNumbers being an arrow function takes the new target of it surrounding just like the case is with this . arrow functions are variable properties not object methods , they therefore don’t have constructors, Where as methods such as
const sumNumbers = function(a, b) {
if (!new.target) throw 'sumNumbers() must be called with new';
this.value a + b;
}
console.log(new sumNumbers(3, 2)); // result: { value: 5}has constructor . expand the console from the above and you would like be greeted by the image below.

Your can read more on how new.target works here
Arrows functions are best suited for non-method functions, and they cannot be used as a constructors.
Our previous examples might have answered this point as well. I would to elaborate more with the example below.
const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea: () => this.height * this.width
}
console.log(shape.getArea()); // result NaNThe example above used array function as a method and considering array function doesn’t have its own this it takes the surrounding environment/scope’s this from the example above, the surrounding scope is global window. Update your code to below and see
this.height = 10;
this.width: 40;const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea: () => this.height * this.width
}
console.log(shape.getArea()); // result 400
Now the array function takes the surrounding scope this . Now consider
const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea: function() {
return this.height * this.width;
}
}
console.log(shape.getArea()) ; //result 45 * 40From the above , getArea is method within an object shape. So this here refers to object shape. And
const shape = {
type: "rectangle",
height: 45,
width: 40,
getArea: function() {
return this.height * this.width;
}
}let area = shape.getArea;
console.log(area()); //result NaN//But console.log(area.bind(shape)()); // result 45 * 40
In the first area, getArea being a method with its own this has no definition for height and width. It doesn’t have definition for any other shape property beside its self too. If you want to pass the this properties, you need to use bind, call or apply.
.call just like ,bind pass this to the calling method and allow passing parameters too. The .apply differs from .call only from the type of parameters passed. .apply allows or permit the passage of array parameters while .call passes individual parameters (i.e . .call(this, a, b), and .apply(this, [a, b]) . And finally .bind(this) is the opposite of the two in the sense that it doesn’t permit the passage of the parameters beside this .
Arrows functions are best suited for non-method functions, what are the example of non-method functions ?
A more practical applications of arrow functions in a non method functions i can think of are
Array manipulations
Consider the example below
const arr = [1, 2, 3, 4, 5];arr.map(x => x +1);arr.forEach((x , i) => {
// logic here});arr.filter(x => x > 2);
etc.
time manipulations
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the Person object
}, 1000);
}
// example taken from mozillafrom the example above, this.age has a definition because an arrow function is used. It takes the age from Person which is it surrounding scope. You might have to use .bind without using the array function because the function would have defined it this .
Promises
Arrow functions are good and mostly use in the application of promises consumption.
promise.then(a => {
// ...
}).then(b => {
// ...
});etc. There are many more example of practical application of arrow functions. These however are what i could think of at the moment . They are clearly discussed in the mozilla article or documentation as well.
To sum it up, i intend to summarised the main differences between array function and the usual js function in this article. Though not a detailed or short summary as i intend it to be, i really hope it out there understand the differences between the two.