Professional Documents
Culture Documents
Search Medium
Get unlimited access to all of Medium for less than $1/week. Become a member
JavaScript is unarguably one of the most popular programming languages in the world and is
used to create interactive websites and web applications. For developers, learning JavaScript
can lead to a wealth of opportunities due to its strength and versatility. In this article, we will
explore 10 key concepts that can help you improve your JavaScript mastery and take your
skills to the next level. These concepts will offer you a strong foundation in the language and
assist you in developing into a more competent and confident developer.
1.Promises
A powerful tool for handling asynchronous actions in your code is JavaScript promises. They
give you a means to deal with the outcomes of an asynchronous operation, like a network
request, without blocking the execution of the rest of your code. A promise can be in one of
three states — fulfilled, rejected, or pending — and it symbolises the final result of an
asynchronous operation.
Promises are used extensively in JavaScript libraries and frameworks, such as AngularJS,
ReactJS, and Node.js. Introduced in ES6, they are a fundamental concept for modern
JavaScript development. Your code’s readability, maintainability, and performance can all be
considerably enhanced by knowing how to use promises correctly.
In using JavaScript promises, the “promise” object is a constructor that creates a new promise
and takes a single argument, which is a function called the "executor". The executor function
takes two parameters, “resolve” and “reject” which can be used to indicate whether the
asynchronous operation has succeeded or failed.
Once a promise is created, you can use its “then” method to attach callbacks that will be
invoked when the promise is resolved, and its “catch” method to attach callbacks that will be
invoked when the promise is rejected. Alternatively, you can manage several promises
simultaneously by using the Promise.all() and Promise.race() methods. Promises are
available in all modern JavaScript environments and are supported in all major browsers, so
you can use them with confidence in your projects.
2. Async/Await
Just like promises, the “async/await ”feature is used in JavaScript to handle asynchronous
operation. It was introduced in ECMAScript 2017 (ES8) and built on top of promises to make
asynchronous code in JavaScript more manageable and easier to read. Async/await offers a
technique for creating asynchronous code with synchronous appearance and behaviour.
An asynchronous function is defined by the “async” keyword. The asynchronous function can
then yield a promise and use the “await” keyword to delay code execution while it waits for
the promise to be fulfilled.
In the code above, “fetch” is an asynchronous function that returns a promise and the “await ”
keyword is used to wait for the promise to resolve before parsing the JSON data.
Using async/await makes your code to be easier to comprehend, maintained, and be more
robust. And as compared to callbacks and promises, it is a more modern, clearer, and
effective way to write asynchronous code.
That being said, it is crucial to note that async/await complements promises, not replaces
them. Simply put, it is a different syntax to perform the same operation. It still relies on
promises to handle the async flow internally.
3. Closures
In JavaScript, inner functions can access the variables and scope of their outer functions
thanks to a key concept called closures. When a function is defined inside another function
and the inner function retains access to the variables and execution scope of the outer
function even after the outer function has completed its execution, a closure is generated.
In this example, the variable x is accessible to the inner function innerFunction from the outer
function’s scope because it is defined inside the outer function outerFunction. The outer
function returns the inner function, which is then assigned to the myClosure variable. The
inner function still has access to the value of x and can return it when called even when the
outer function’s execution is complete.
Closures in JavaScript are commonly used for a variety of tasks, including the creation of
private variables, the application of functional programming paradigms, and the creation of
closures in loops. By enabling functions to carry data with them, closures can also be utilised
to build robust and expressive code. Also in JavaScript, it can be used to implement object-
oriented programming patterns.
Nonetheless, closures can also result in memory leaks if not used appropriately, as the inner
function continues to maintain a reference to the variable and scope of the outer function
and the garbage collector is unable to release the memory.
4. Prototypal Inheritance
In contrast to the class-based inheritance model used in languages like Java and C#,
JavaScript uses a prototype-based model of inheritance. In JavaScript, objects inherit their
properties and methods from other objects rather than from classes.
Each JavaScript object has an internal property called __proto__ (or [[Prototype]]), which
points to a different object known as the “prototype object.” When an object’s properties or
methods are accessed, JavaScript first determines whether the object itself has the property
or method defined directly on it. If it doesn’t, JavaScript checks the object’s prototype object
and keeps searching through the prototype chain until it either finds the property or method
or reaches the end of the chain.
You will observe from the code above that the “dog” object in this example inherits the “eats”
attribute from “animal”, its prototype object, rather than having it specified directly on it.
This is how prototypal inheritance works. It is a mechanism wherein objects can inherit the
properties and methods from other objects.
It is essential to note here that the inheritance in this context is dynamic and not static,
meaning that you can modify the prototype object by adding or removing properties and
methods, and the objects that derive from it will update to reflect the changes.
5. Currying
Currying in JavaScript is a technique that enables partial application of a function by pre-
filling some of its arguments. This allows function calls to be reused and flexible.
Consider a function that accepts the two arguments x and y and returns their total as an
example.
1 function add(x, y) {
2 return x + y;
3 }
4 console.log(add(2, 3)); // 5
Using closures, we can change this function into a curried function that accepts the
remaining argument.
1 function add(x) {
2 return function(y) {
3 return x + y;
4 }
5 }
6 const add2 = add(2);
7 console.log(add2(3)); // 5
In this illustration, the initial use of add(2) yields a new function that accepts the final
argument, y. Since the x and y values are already set to 2 and 3, respectively, when add2(3) is
called, the result is 5.
The spread operator and arrow functions can also be used to achieve currying. Let’s take a
look at an example below:
In this illustration, the first call to add(2) produces a new arrow function that adds x and y to
any remaining arguments, regardless of their number.
Currying can increase the re-usability and readability of code while also allowing function
calls to be more flexible.
6. Higher-Order Functions
Higher-order functions in JavaScript are those that accept one or more functions as
arguments and/or return another function as their output. As they can be used as any other
variable or value, these functions are also referred to as “first-class functions.” The term
“higher-order” indicates a higher of level of abstraction than the usual JavaScript function.
v. setTimeout(): This function accepts a callback function as an input and schedules its
execution for a given amount of time in the future.
vi. Promise.then(): This function accepts a callback function as an input and schedules its
execution for when a promise is resolved.
The filter() function in this example receives an anonymous function as a callback and uses it
to determine whether each element in the array is even before returning only the even
numbers.
7. Generators
These are a special type of function in JavaScript that allow for execution pauses and restarts.
They are helpful when working with iterators and asynchronous programs since they let you
construct a sequence of values over time.
A generator function is defined using the function* keyword and uses the yield keyword to
pause execution and return a value. When the generator function is invoked, it produces an
iterator object that can be used to control the generator’s execution.
Assuming we want to create a generator function that returns the next number in the
Fibonacci sequence:
1 function* fibonacci() {
2 let [a, b] = [0, 1];
3 while (true) {
4 yield a;
5 [a, b] = [b, a + b];
6 }
7 }
8
9 const fib = fibonacci();
10 console.log(fib.next().value); // 0
11 console.log(fib.next().value); // 1
12 console.log(fib.next().value); // 1
13 console.log(fib.next().value); // 2
In the above example, the function* keyword is used to declare the generator function
fibonacci(). It uses the yield keyword to return the current value of a and updates the values
of a and b using destructuring assignment. The while loop ensures that the generator will
continue to produce new values indefinitely.
The generator function, when invoked, returns an iterator object that can be used to control
the generator’s execution. The next() method is used to resume execution and return the next
value.
Large data sets, asynchronous code, iterators, and infinite sequences can all be implemented
with the help of generators. Without having to load all the data into memory at once, they
enable you to generate a succession of values over time.
On the other hand, a WeakSet is similar to a Set but exhibits the same weak referencing
behaviour for its components. This means that if there are no other references to an element
in a WeakSet, it can be garbage collected.
Both WeakMap and WeakSet are helpful for managing JavaScript memory usage because they
let you store information without storing it in memory permanently.
9. Proxies
Objects that serve as intermediaries between the code that accesses them and the underlying
objects they represent are known as proxies. They give you the ability to modify and intercept
operations made on the underlying object, such as method calls, constructors, and property
access.
The following code is an example of how a proxy can be used to intercept property access:
In this example, an object called obj is wrapped in a Proxy object. To handle property access
and assignment, we define two “handler” functions, “get” and “set”. We can intercept and
change the behaviour of the underlying object using these functions. The “get” function will
be called, a message will be logged, and the value of the “name” property from the original
object will be returned when we access the name property of the proxy object.
You can also use Proxies to create “virtual” objects that do not have a direct representation in
memory, such as lazy-loading properties or data from an API.
Here is another example of how to use the Reflect API to determine whether or not an object
is extensible:
This example shows how to check the extensibility of an object using the
Reflect.isExtensible() method. Due to its extensible nature by default, it initially returns true.
Following that, we use Object.preventExtensions(obj) to stop the object from being extended.
Next, we use Reflect.isExtensible(obj) once more, which returns false to indicate the object is
no longer extensible.
Reflect.get()
Reflect.set()
Reflect.has()
Reflect.deleteProperty()
Reflect.defineProperty()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.setPrototypeOf()
Reflect.preventExtensions()
Reflect.isExtensible()
Reflect.apply()
Reflect.construct()
Reflect API is typically used when you want to produce more robust and maintainable code or
when you want to conduct operations on an object in a more consistent and predictable
manner.
Coding artisan and educator, dedicated to crafting elegant and innovative applications that merge form with function.
Sodiq Akanmu
Do More with Less: 10 Advanced JavaScript Syntax to Write Clean and Efficient
Code with Brevity
I received great feedback from readers of one of my most recent articles, “10 concepts to improve your
mastery of JavaScript”, regarding…
352 4
Sodiq Akanmu
116 5
Sodiq Akanmu
The 10 Deadly Sins of JavaScript Programming: Common Errors You Must Avoid
Have you ever spent hours debugging your JavaScript code only to find out that the problem was really
just a simple oversight that you…
55 1
Sodiq Akanmu
105 1
326 7
Sodiq Akanmu
Do More with Less: 10 Advanced JavaScript Syntax to Write Clean and Efficient
Code with Brevity
I received great feedback from readers of one of my most recent articles, “10 concepts to improve your
mastery of JavaScript”, regarding…
352 4
Lists
Staff Picks
310 stories · 77 saves
1K 5
FardaKarimov in JavaScript in Plain English
94 1
985 18
Avinash Vagh
411 4