skip to content
Home Image
Table of Contents

JavaScript Function Advanced

This section covers advanced function topics in JavaScript.

These chapters are best after you understand basic functions (calling, parameters, return values, expressions, and arrows).

Function Definitions

  1. Function Declarations
function functionName(parameters) {
// code to be executed
}

Function Declaration refers specifically to a standalone statement that defines a named function using the function keyword. It is hoisted, meaning it is available throughout its scope before any code is executed

Function Definitions vs Function Declarations

Function declaration is one specific way to define a function.

Function Definition is a broader term that encompasses both function declarations and function expressions. It refers to the act of creating a function, including its name, parameters, and body. In practice, “function definition” may include:

Examples of function definitions include:

a. Function declarations

b. Function expressions

c. Arrow functions

Declarations vs Expressions

Function Expression assigns a function to a variable and may be anonymous:

const greet = function() {
return "Hello!";
};

Functions are Objects

The typeof operator in JavaScript returns “function” for functions.

But, JavaScript functions can best be described as objects.

JavaScript functions have both properties and methods.

Function this

Q. What is this?

When the this keyword is used in a function, it refers to an Object.

Which Object, is not decided when the function is written.

The value of this is decided when the function is called.

  1. this in an Object Method

When a function is an object method:

this refers to the object that owns the method.

const person = {
firstName: "John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
};
person.fullName();

In the example above, this refers to the person object.

this.firstName means the firstName property of person.

this.firstName is the same as person.firstName.

  1. this in Event Handlers

In HTML event handlers, this refers to the HTML element that received the event:

<button onclick="this.innerHTML='Clicked!'">Click Me</button>
  1. this in Arrow Functions

Arrow functions do not have their own this. They inherit this from the surrounding scope.

In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.

With arrow functions the this keyword always represents the object that defined the arrow function.

JavaScript Function call

The call() method can be used to call a function with a specific this.

The call() method lets an object use a method belonging to another object.

In this way, the same method can be used on different objects.

functionName.call(this, arg1, arg2, ...);

call() vs Normal Function Call

function showName() {
return this.name;
}
const person = { name: "John" };
showName();
showName.call(person);

Without call(), this is not the person object.

With call(), this is set explicitly.

Function Apply

The apply() method lets you write a method that can be used on different objects.

The apply() method is used to call a function with a specific this.

The apply() method is similar to call(), but it passes arguments in an array.

functionName.apply(this, [arg1, arg2, ...]);
  1. Using apply() to Set this

When you use apply(), you can decide what this should refer to.

const person1 = { name: "John" };
const person2 = { name: "Paul" };
const person3 = { name: "Ringo" };
function greet(greeting) {
return greeting + " " + this.name;
}
greet.apply(person3, ["Hello"]);
result :
Hello Ringo

Difference Between call() and apply()

The only difference between apply() and call() is how arguments are passed.

The call() method takes arguments separately.

The apply() method takes arguments as an array.

greet.call(person, "Hello");
greet.apply(person, ["Hello"]);

Function bind

Like with call() and apply(), the bind() an object can borrow a method from another object.

Unlike call() and apply(), the bind() method does not run the function immediately.

Instead, it returns a new function that can be called later.

The new function remembers the this value you choosed.

const newFunction = functionName.bind(this, arg1, arg2, ...);
  1. Using bind() to Fix this

The most common use of bind() is to make sure a function always uses the same this value.

const person1 = { name: "John" };
const person2 = { name: "Paul" };
const person3 = { name: "Ringo" };
function greet() {
return "Hello " + this.name;
}
const greetJohn = greet.bind(person1);
greetJohn();

greetJohn is a new function that always uses person1 as this.

bind() vs call() and apply()

The difference between these methods is important:

a. call() calls a function immediately

b. apply() calls a function immediately

c. bind() returns a new function

  1. bind() for Functions Called Later

Without bind(), the this value may be lost.

const person = {
name: "John",
sayHello: function() {
return "Hello " + this.name;
}
};
const hello = person.sayHello;
hello(); // this is not person

The function above loses its this value.

  1. Using bind() for Preserving this

The bind() method can be used to prevent losing this.

In the following example, the person object has a display method.

In the display method, this refers to the person object:

const person = {
firstName:"John",
lastName: "Doe",
display: function () {
let x = document.getElementById("demo");
x.innerHTML = this.firstName + " " + this.lastName;
}
}
person.display();

When a function is used as a callback, this is lost.

  1. bind() with Arguments

Arguments passed to bind() become fixed values.

This is sometimes called partial application.

function multiply(a, b) {
return a * b;
}
const double = multiply.bind(null, 2);
double(5);

The double function will always multiply by 2.

Function Closer

JavaScript variables can belong to:

The local scope or The global scope

Global variables can be made local (private) with closures.

Closures makes it possible for a function to have “private” variables.

A closure is created when a function remembers the variables from its outer scope, even after the outer function has finished executing.

  1. Local Variables

A local variable is a “private” variable defined inside a function.

A function can access all variables in the local scope.

function myFunction() {
let a = 4;
return a * a;
}
  1. Global Variables

A global variable is a “public” variable defined outside a function.

A function can access all variables in the global scope:

let a = 4;
function myFunction() {
return a * a;
}

JavaScript Object Advanced

JavaScript Object Definitions

  1. Using an Object Literal

An object literal is a list of property key:values inside curly braces { }.

// Create an Object
const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
  1. JavaScript Object.create()

The Object.create() method creates an object from an existing object.

// Create an Object:
const person = {
firstName: "John",
lastName: "Doe"
};
// Create new Object
const man = Object.create(person);
man.firstName = "Peter";
  1. JavaScript Object fromEntries()

The fromEntries() method creates an object from iterable key / value pairs.

const fruits = [
["apples", 300],
["pears", 900],
["bananas", 500]
];
const myObj = Object.fromEntries(fruits);
  1. JavaScript Object.assign()

The Object.assign() method copies properties from one or more source objects to a target object.

// Create Target Object
const person1 = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
// Create Source Object
const person2 = {firstName: "Anne",lastName: "Smith"};
// Assign Source to Target
Object.assign(person1, person2);

JavaScript Class Advanced

JavaScript Classes

  1. JavaScript Class Syntax

Use the keyword class to create a class.

Always add a method named constructor():

class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
}
  1. Using a Class

a. Normal Method

const myCar1 = new Car("Ford", 2014);
const myCar2 = new Car("Audi", 2019);

b. The Constructor Method

Always add a constructor() method.

Then add any number of methods.

class Car {
//constructor
constructor(name, year) {
this.name = name;
this.year = year;
}
// method
age() {
const date = new Date();
return date.getFullYear() - this.year;
}
}
const myCar = new Car("Ford", 2014);
document.getElementById("demo").innerHTML =
"My car is " + myCar.age() + " years old.";

JavaScript Class Inheritance

To create a class inheritance, use the extends keyword.

A class created with a class inheritance inherits all the methods from another class:

class Car {
constructor(brand) {
this.carname = brand;
}
present() {
return 'I have a ' + this.carname;
}
}
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
show() {
return this.present() + ', it is a ' + this.model;
}
}
let myCar = new Model("Ford", "Mustang");
document.getElementById("demo").innerHTML = myCar.show();

The super() method refers to the parent class.

By calling the super() method in the constructor method, we call the parent’s constructor method and gets access to the parent’s properties and methods.

  1. Getters and Setters

Classes also allow you to use getters and setters.

It can be smart to use getters and setters for your properties, especially if you want to do something special with the value before returning them, or before you set them.

To add getters and setters in the class, use the get and set keywords.

class Car {
constructor(brand) {
this.carname = brand;
}
get cnam() {
return this.carname;
}
set cnam(x) {
this.carname = x;
}
}
const myCar = new Car("Ford");
document.getElementById("demo").innerHTML = myCar.cnam;

JavaScript Static Methods

Static class methods are defined on the class itself.

You cannot call a static method on an object, only on an object class.

class Car {
constructor(name) {
this.name = name;
}
static hello() {
return "Hello!!";
}
}
const myCar = new Car("Ford");
// You can call 'hello()' on the Car Class:
document.getElementById("demo").innerHTML = Car.hello();
// But NOT on a Car Object:
// document.getElementById("demo").innerHTML = myCar.hello();
// this will raise an error.

JavaScript Asynchronous Advanced

JavaScript Control Flow

Control Flow is the order in which statements are executed in a program.

By default, JavaScript runs code from top to bottom and left to right.

Control flow statements let you change that order, based on conditions, loops or keywords.

  1. Default Flow

Default flow executes code sequentially (from top to bottom / from left to right).

let x = 5;
let y = 6;
let z = x + y;
Flow sequentially: let x → let y → let z.
  1. Conditional Control Flow

Conditions let you make decisions using:

if
if...else
switch
ternary (? :)
  1. Loops (Repetition Control Flow)

Loops let you run code multiple times using:

for
while
do...while
  1. Jump Statements
Jump statements let you change the flow abruptly using:
break - exits a loop or switch
continue - skips the current loop iteration
return - exits from a function
throw - jumps to error handling
  1. Function Flow

Functions are callable and reusable code blocks:

Function to compute the product of two numbers:
function myFunction(p1, p2) {
return p1 * p2;
}

JavaScript Is Single-Threaded

JavaScript runs on a single thread.

It can only do one thing at a time.

Every task has to wait for the previous one to finish.

This can freeze an application during slow operations (like file requests).

Asynchronus Flow JavaScript Asynchronous Flow refers to how JavaScript handles tasks that take time to complete, like reading files, or waiting for user input, without blocking the execution of other code.

To prevent blocking, JavaScript can use asynchronous programming.

This allows certain operations to run in the background, and their results are handled later, when they are ready.

Callbacks

A callback is a function passed as an argument to another function

This technique allows a function to call another function

A callback function can run after another function has finished

  1. Function Sequence

JavaScript functions are executed in the sequence they are called. Not in the sequence they are defined.

This example will display “Hello”, but end up with “Goodbye” because the functions are called in that order:

function myFirst() {
myDisplayer("Hello");
}
function mySecond() {
myDisplayer("Goodbye");
}
myFirst();
mySecond();
  1. Sequence Control

Sometimes you would like to have better control over when to execute a function.

Suppose you want to do a calculation, and then display the result.

You could call a calculator function (myCalculator), save the result, and then call another function (myDisplayer) to display the result:

function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}
function myCalculator(num1, num2) {
let sum = num1 + num2;
return sum;
}
let result = myCalculator(5, 5);
myDisplayer(result);
  1. JavaScript Callbacks

Using a callback, you could call the calculator function (myCalculator) with a callback (myCallback), and let the calculator function run the callback after the calculation is finished:

function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}
function myCalculator(num1, num2, myCallback) {
let sum = num1 + num2;
myCallback(sum);
}
myCalculator(5, 5, myDisplayer);

Q. When to Use a Callback?

The examples above are not very exciting.

They are simplified to teach you the callback syntax.

Where callbacks really shine are in asynchronous functions, where one function has to wait for another function (like waiting for a file to load).

Asynchronous functions are covered in the next chapter.

Asynchronous JavaScript

Functions running in parallel with other functions are called asynchronous.

Some tasks run in the background, and JS doesn’t wait for them to finish. Instead, it keeps going and comes back later when the task is done.

A good example is JavaScript setTimeout()

console.log("Start");
setTimeout(() => {
console.log("Async task done");
}, 1000);
console.log("End");
// consoles
Start
End
Async task done

JavaScript Promises

A Promise in JavaScript is an object that represents the eventual result of an asynchronous operation — either a success (with a value) or a failure (with a reason). It lets asynchronous methods return values in a way that feels like synchronous code by allowing you to attach handlers for when the operation completes or fails.

A Promise can have 3 states:

a. Pending – initial state, not yet finished (no result yet).

b. Fulfilled – the operation finished successfully and produced a value.

c. Rejected – the operation failed and produced a reason (usually an error).

Creating a Promise (Promise Constructor)

const promise = new Promise((resolve, reject) => {
// asynchronous work here
if (successful) {
resolve(result); // fulfills the promise
} else {
reject(error); // rejects the promise
}
});

The constructor takes one argument: an executor function.

The executor function receives two callbacks:

resolve(value) — fulfills the promise with value.

reject(reason) — rejects the promise with reason.

resolve and reject are only available inside the executor.

Handling Promise Results

Once a promise is created, you attach handlers to deal with the result:

.then(onFulfilled, onRejected)
. Runs when promise fulfills or rejects.
. Optional second argument handles rejection.
. Returns a new promise, enabling chaining.
promise.then(
value => console.log("Result:", value),
error => console.error("Error:", error)
);
.catch(onRejected)
. Shortcut for handling only rejected cases.
. Equivalent to promise.then(undefined, onRejected).
promise.catch(error => console.error("Caught error:", error));
.finally(onFinally)
. Runs after the promise settles — whether it fulfilled or rejected.
. Useful for cleanup work (e.g., hiding a loading spinner).
. Always returns a new promise with the same outcome as the original.
promise.finally(() => console.log("Done (either success or failure)"));

Promise Chaining

because .then, .catch, and .finally all return new promises, you can chain them:

promise
.then(step1)
.then(step2)
.catch(handleError)
.finally(cleanUp);

Static Promise Methods

These are methods on the Promise class (not on promise instances):

MethodWhat it Does
Promise.all(iterable)Waits for all promises to fulfill, or fails fast on first reject.
Promise.allSettled(iterable)Waits until all settle, returns an array of results.
Promise.any(iterable)Fulfills if any promise fulfills; rejects only if all reject.
Promise.race(iterable)Settles as soon as the first promise settles.
Promise.resolve(value)Returns a promise resolved with the value.
Promise.reject(reason)Returns a promise rejected with the reason.
Promise.withResolvers()Returns an object with a promise and its resolve/reject functions.

JavaScript Asyn/Wait

“async and await make promises easier to write”

async makes a function return a Promise

await makes a function wait for a Promise

  1. Async Syntax

The keyword async before a function makes the function return a promise:

async function myFunction() {
return "Hello";
}
  1. Await Syntax

The await keyword can only be used inside an async function.

The await keyword makes the function pause the execution and wait for a resolved promise before it continues:

let value = await promise;