Difference between Normal and Arrow Functions

Reading Time: 3 minutes

Arrow functions have been adopted since ECMAScript 2015. They are very powerful and simple. Many ES5-based projects adopted this feature to refactor the code. However, the arrow functions aren’t the same as the normal functions you’ve got to know. In this blog, I will explain what is the difference between normal and arrow functions.

This Keyword

A normal functions .this – binding is determined by who calls the function:

let a = 10;
let obj = { 
  hello,
  a: 20
};

function hello() {
  console.log(this.a);
}

hello(); // outputs 10
obj.hello(); //outputs 20

The method hello gives a different result by how it’s called. This is because a normal functions this is bound to the object that calls the function.

In contrast to a normal function, an arrow functions this is always bound to the outer function that surrounds the inner function:

let a = 10;
let hello = () => { 
  console.log(this.a);
};

let obj = {
  hello,
  a: 20
}

hello(); // outputs 10
obj.hello(); //outputs 10

In this example, hello is an arrow function. It’s a property of the obj. Even though obj calls hello, it still prints 10 because a function’ this always refers to the outer environments this. And the global this is a window so it points out to window.x.

Arguments

A normal function has a special property called argument:

function hello () {
  console.log(arguments.length)
};

hello(1, 2, 3); // outputs 3

hello(10); // outputs 1

An arrow function doesn’t have an arguments property:

let hello = () => {
  console.log(arguments.length)
};

hello(1, 2, 3); // outputs arguments is not defined

Binds

function.prototype.bind is a method you can use to change the this of the function:

let car = ‘Volvo’ 

function whatCar() {
  console.log(this.car)
};

whatCar(); // outputs ‘Volvo’
whatCar.bind({car: ‘Nissan’})() // outputs ‘Nissan’

whatCar prints the value depending on the assigned this.

But an arrow function doesn’t work with function.prototype.bind because it doesn’t have a local thisBinding. So it just looks at the outer environments this:

let car = ‘Volvo’ 

let whatCar = () => {
  console.log(this.car)
};

whatCar(); // outputs ‘Volvo’
whatCar.bind({car: ‘Nissan’})() // outputs ‘Volvo

Constructor

Normal function can be constructible and callable and arrow function is only callable and not constructible, they can never be invoked with the new keyword:

function hello () {};
let hi = () => {};
new hello(); // works
 hi(); // outputs hi is not a constructor

Arrow functions are more handy and stylish, but there are differences between arrow function and normal function. Maybe an arrow function won’t always be the best option to use. All I want to say is the best way to choose what function to use depends on each situation.

What to expect from ECMAScript in 2019

Reading Time: 5 minutes

JavaScript as a language has been maturing at a steady pace in the past decade with the evolution of ECMAScript. The current version was released in June 2018, ES2018 and the upcoming version brings several new additions to the language which we’ll cover in this post.

Before that, it can be useful to know how new features are being added to the language through the additions to the ECMAScript standard.

ECMAScript proposals

The Technical Committee 39, TC39, is responsible for reviewing and adopting changes to the existing version of the ECMAScript standard. The process takes the form of 5 stages of maturity after which a new feature is included in the standard.

  • Stage 0: Strawman
  • Stage 1: Proposal
  • Stage 2: Draft
  • Stage 3: Candidate
  • Stage 4: Finished

There is no guarantee that a feature in Stage 3 will be included in the standard, but generally, JavaScript engine implementations like V8 (Chrome, Node.js, Opera), SpiderMonkey (Firefox) and Chakra (Microsoft Edge) tend to add some features with experimental support so that developers can test and provide feedback.

ES2019 finished features

At the time of writing this post, there have been several finished features, you can check the full list in the TC39 proposal repository.

  • Array.prototype.{flat, flatMap}
  • Object.fromEntries()
  • String.prototype.{trimStart, trimEnd}
  • Symbol.prototype.description
  • Subsume JSON
  • Optional catch binding
  • Well-formed JSON.stringify()
  • Function.prototype.toString()

Array.prototype.{flat, flatMap}

The new array instance method, flat(), flattens an array up to a given value, it takes an optional depth argument which can be set to Infinity to run recursively until the array is single dimensional.

const nestedArray = ["a", ["b", "c"], ["d", ["e", ["f"]]]];

// using flat() on a multidimensional array
nestedArray.flat();
["a", "b", "c", "d", ["e", ["f"]]]

// using flat() with an argument
nestedArray.flat(2);
["a", "b", "c", "d", "e", ["f"]]

// using flat() with Infinity as argument
nestedArray.flat(Infinity);
["a", "b", "c", "d", "e", "f"]

flatMap() is similar to the existing map() method, but the callback can return an array and the end result will be a single dimensional array instead of nesting arrays.

const scatteredArray = ["a b c", "d", "e f", "g"];

// map() results in nested arrays
scatteredArray.map( chunk => chunk.split(" "));
[["a", "b", "c" ], [ "d" ], [ "e", "f" ], [ "g" ]]

// flatMap() concatenates the returned arrays together
scatteredArray.flatMap( chunk => chunk.split(" "));
["a", "b", "c", "d", "e", "f", "g"]

Object.fromEntries()

Objects have an entries() method since ES2017, it returns an array key-value pairs of the object’s properties. The fromEntries() method does the reverse and returns an object from an array of properties.

If we use both methods on an object the cloned object will be copied by reference.

const person = { name: "John", age: 30, country: "UK" }

// using Object.entries and assigning it to a new object
const entries = Object.entries(person)
[["name", "John" ], [ "age", 30 ], [ "country, "UK" ]]

// using the new Object.fromEntries
const newPerson = Object.fromEntries(entries)
{ name: "John", age: 30, country: "UK" }

// the new object is a shallow copy
person !== newPerson
true

String.prototype.{trimStart, trimEnd}

trimStart() returns a string with removed whitespaces from the start of the original string, while trimEnd() removes whitespaces from the end.

const str = "   blank spaces   ";

// trimStart() usage
str.trimStart();
"blank spaces   "

// trimEnd() usage
str.trimEnd();
"   blank spaces"

Symbol.prototype.description

When creating a symbol, you can now retrieve its description property instead of using toString() on the object.

const symbol = Symbol("This is the symbol description")

// retrieving the description property
symbol.description;
"This is the symbol description"

Subsume JSON

This proposal solves an issue of inconsistency between a JSON and an ECMAScript JSON, which by specification should be a superset of a JSON.

JSON strings currently accept unescaped U+2028 and U+2029 characters, while ECMAScript strings don’t. With this extension of the ECMAScript JSON, this gap will be patched.

Optional catch binding

In previous versions of ECMAScript, we had to implement a catch binding even if we never had to use it.

try {
  // ...
} catch (error) {
  // handle error
}

With this addition, we can now simply omit it.

try {
  // ...
} catch {
  // handle error
}

Well-formed JSON.stringify()

This fixes the JSON.stringify() output when it processes surrogate UTF-8 code points (U+D800 to U+DFFF). Before this change calling JSON.stringify() would return a malformed Unicode character (a “�”).

Now those surrogate code points can be safely represented as strings using JSON.stringify() and transformed back into their original representation using JSON.parse().

Function.prototype.toString()

ES2019 introduces a change to the toString instance method of functions. Now the returned value will be exactly as defined, without stripping whitespaces and comments.

function /* this is foo */ foo () {}

// previous behavior of toString()
foo.toString()
"function foo () {}"

// proposal behavior
foo.toString()
"function /* this is foo */ foo () {}"

Upcoming candidate features

The following list contains all current candidate features which have reached Stage 3 and will most likely be included in the specification in the future.