Last modified: December 10, 2024
This article is written in: 🇺🇸
JavaScript is a programming language that is primarily used for client-side scripting (making web pages interactive). Since NodeJS we can also use JavaScript in server-side scripting (e.g. for APIs).
Main idea:
The following are the fundamental concepts of JavaScript:
You can either inline JavaScript or include refrence to an external JavaScript file:
<script>
tags:
<script>
// JavaScript code goes here
</script>
<script>
tag:
<script crossorigin="anonymous" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
var x;
console.log(x); // undefined
var y = null;
console.log(y); // null
console.log(typeof x); // undefined
console.log(typeof y); // object
console.log(x === y); // false
console.log(x == y); // true
A few useful built-in methods that you can use in JavaScript:
console.log()
- to display messages in the consolealert()
- to display a message in an alert boxprompt()
- to get input from the userconfirm()
- to ask the user a question and get a yes or no answerparseInt()
- to convert a string to an integerparseFloat()
- to convert a string to a floating point numberisNaN()
- to check if a value is not a numberisFinite()
- to check if a value is a finite numberNumber()
- to convert a string to a numberString()
- to convert a number to a stringBoolean()
- to convert a value to a booleanArray()
- to convert a value to an arrayObject()
- to convert a value to an objectDate()
- to get the current date and timeLet's take a look at some examples:
var name = prompt("Enter your name");
alert("Hello " + name);
Some of the most common number operations:
number.toFixed(n)
- returns a string with n decimal places for a variable named numbernumber.toPrecision(n)
- returns a string with n significant digits for a variable named numbernumber.valueOf()
- returns the number as a primitive valueparseInt(string)
- returns the first number in the stringparseFloat(string)
- returns the first floating point number in the stringNumber.MAX_VALUE
- largest possible JS numberNumber.MIN_VALUE
- smallest possible JS numberNumber.NEGATIVE_INFINITY
- -InfinityNumber.POSITIVE_INFINITY
- InfinityLet's parse a floating point number from a string and display it with two decimal places:
var pi = parseFloat("3.14159");
console.log(pi.toFixed(2));
Some of the most common math functions:
Math.round(n)
- rounds a number n to the nearest integerMath.pow(x,y)
- returns x to the power of yMath.sqrt(n)
- returns the square root of nMath.abs(n)
- returns the absolute value of nMath.ceil(n)
- returns the smallest integer greater than or equal to nMath.floor(n)
- returns the largest integer less than or equal to nMath.sin(n)
- returns the sine of nMath.cos(n)
- returns the cosine of nMath.min(n1, n2, ...)
- returns the smallest of the given numbersMath.max(n1, n2, ...)
- returns the largest of the given numbersMath.log(n)
- returns the natural logarithm of nMath.exp(n)
- returns the value of E to the power of nMath.random()
- returns a random number between 0 and 1In the example below we use the Math.random()
function to generate a random number between 0 and 1 and then display the value of sine function at that point:
var x = Math.random();
var y = Math.sin(x);
console.log(y);
The comparison operators are used to compare two values.
Operator | Description |
== |
Equal to |
=== |
Strictly equal to |
!= |
Not equal to |
!== |
Strictly not equal to |
< |
Less than |
> |
Greater than |
<= |
Less than or equal to |
>= |
Greater than or equal to |
In the example below we compare two numbers:
var x = 10;
var y = 20;
console.log(x == y); // false
console.log(x < y); // true
The logical operators are used to combine two or more conditions.
Operator | Description |
&& |
Logical AND |
|| |
Logical OR |
! |
Logical NOT |
In the example below we use logical operators to check if a number is greater than 10 and at the same time less than 20:
var x = 15;
var y = 20;
console.log(x > 10 && x < 20); // true
console.log(y > 10 && y < 20); // false
The conditionals are used to execute different code depending on the value of a variable.
Operator | Description |
if |
Execute code if a condition is true |
else |
Execute code if a condition is false |
else if |
Execute code if a condition is false and another condition is true |
In the example below we use conditionals to check if a number is greater than 10 and at the same time less than 20:
var x = prompt("Enter a number");
if (x > 10 && x < 20) {
console.log("The number is between 10 and 20");
} else {
console.log("The number is not between 10 and 20");
}
The while loops are used to execute a block of code as long as a condition is true.
Operator | Description |
while |
Execute code as long as a condition is true |
In the example below we use a while loop to count from 1 to 10:
var i = 1;
while (i <= 10) {
console.log(i);
i++;
} // 1 2 3 4 5 6 7 8 9 10
The for loops are used to execute a block of code a number of times.
Operator | Description |
for |
Execute code a number of times |
In the example below we use a for loop to count from 1 to 10:
for (var i = 1; i <= 10; i++) {
console.log(i);
}
A function is a named block of code that performs a specific task. We already used built-in functions like alert()
and prompt()
to display messages and get input from the user. Each function has to be first defined and then called. Once defined, the function can be called as many times as needed.
In the example below we create a function that calls the console.log() two times:
// Function definition
function sayHello() {
console.log("Hello");
console.log("World");
}
sayHello(); // Function call
The function arguments are the values that are passed to the function when it is called.
In the example below we create a function that takes two arguments and adds them together:
// Function definition
function add(x, y) {
console.log(x + y);
}
// Function call
add(10, 20); // 30
The "return" keyword is used to return a value from a function.
In the example below we create a function that takes two arguments and adds them together:
// Function definition
function add(x, y) {
return x + y;
}
// Function call
var result = add(10, 20);
console.log(result); // 30
Arrow functions are a new way to define functions in JavaScript. They are a shorter syntax for writing function definitions.
In the example below we create a function that takes two arguments and adds them together:
// ES5
function add(x, y) {
return x + y;
}
// ES6
const add = (x, y) => {
return x + y;
}
The scope of a variable is the part of a program where that variable can be accessed.
Variable Type | Scope | Mutability | Hoisting | Description | Best Practices |
var |
Global or function | Mutable | Hoisted but initialized as undefined |
- var is function-scoped, meaning it’s accessible throughout the function where it’s declared.- Variables declared with var are hoisted to the top of their scope, meaning they are accessible before their declaration (with an undefined value).- Can be redeclared within the same scope. |
Avoid using var due to potential issues with scope and hoisting. Instead, use let or const . |
let |
Block | Mutable | Hoisted but not initialized | - let is block-scoped, meaning it’s only accessible within the block (e.g., inside a loop or conditional statement) where it’s declared.- While let variables are hoisted, they are not initialized, so referencing them before declaration results in a ReferenceError .- Can’t be redeclared in the same scope. |
Use let when you expect the variable value to change later in the code. |
const |
Block | Immutable (value cannot be reassigned) | Hoisted but not initialized | - const is also block-scoped and follows the same scoping and hoisting rules as let .- Values assigned to const cannot be reassigned. However, if the value is an object or array, its properties or elements can still be modified.- Can’t be redeclared in the same scope. |
Use const by default when you don’t plan to reassign the variable, as it provides more predictable behavior. |
In the example below we create a variable that is accessible from anywhere in the program:
var x = 10;
function add(y) {
return x + y;
}
console.log(add(20)); // 30
In the example below we create a variable that is accessible only from within the block:
var x = 10;
{
var a = 20;
let b = 15;
console.log(a + b); // 35
}
function add(y) {
return x + y;
}
console.log(add(a)); // 30
console.log(add(b)); // Uncaught ReferenceError: y is not defined
Higher-order functions are functions that take other functions as arguments or return functions.
In the example below we create a function that takes another function as an argument:
function add(x, y) {
return x + y;
}
function multiply(x, y) {
return x * y;
}
function doMath(x, y, callback) {
return callback(x, y);
}
console.log(doMath(2, 3, add)); // 5
console.log(doMath(2, 3, multiply)); // 6
Arrays are used to hold several values under a single name and to organize them using indexes represented by consecutive integers.
Let's create an array of numbers:
var numbers = [1, 2, 3, 4, 5];
console.log(numbers); // [1, 2, 3, 4, 5]
Let's let the user enter a number and add it to the array:
var numbers = [];
for (var i = 0; i < 5; i++) {
var number = prompt("Enter a number");
numbers.push(number);
}
console.log(numbers);
The array can be copied using the .slice()
method:
var numbers = [1, 2, 3, 4, 5];
var numbersCopy = numbers.slice();
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(numbersCopy); // [1, 2, 3, 4, 5]
To copy only a part of the array, use the .slice()
method with two arguments:
var numbers = [1, 2, 3, 4, 5];
console.log(numbers.slice(1, 3)); // [2, 3]
The array can be modified using the .push()
and .pop()
methods:
var numbers = [1, 2, 3, 4, 5];
numbers.push(6);
console.log(numbers); // [1, 2, 3, 4, 5, 6]
numbers.pop();
console.log(numbers); // [1, 2, 3, 4, 5]
Methods that return a new value or representation are known as accessor methods.
.join()
- Joins all elements of an array into a string..reverse()
- Reverses the order of the elements in an array..sort()
- Sorts the elements of an array..concat()
- Combines two or more arrays..slice()
- Extracts a part of an array..indexOf()
- Searches an array for an element..lastIndexOf()
- Searches an array for an element from the end.In the example below we first use concat() to combine two arrays, then we sort the result and finally we call the join() method to join the elements of the array into a string:
var numbersA = [5, 6, 2, 1, 8];
var numbersB = [9, 7, 1, 10, 4];
var numbers = numbersA.concat(numbersB);
numbers.sort();
console.log(numbers.join()); // 1,1,2,4,5,6,7,8,9,10
The array can be iterated using the .forEach()
method:
var numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(number) {
console.log(number);
});
Strings are sequences of characters. They are used to represent text. We use single or double quotes to create strings.
An example of a string is:
var name = "John";
console.log(name); // John
Some of common string methods include:
.indexOf()
- Searches a string for a specified value and returns the position of the match..lastIndexOf()
- Searches a string for a specified value and returns the position of the match..slice()
- Extracts a part of a string and returns the extracted part in a new string..replace()
- Finds a match between a regular expression and a specified string, and returns a new string with the matches replaced..toUpperCase()
- Converts a string to upper case..toLowerCase()
- Converts a string to lower case..concat()
- Combines two or more strings..charAt()
- Returns the character at the specified index (position) of a string..charCodeAt()
- Returns the Unicode of the character at the specified index (position) of a string.Lets slice the string "John loves JavaScript" from index 5 to index 10:
var text = "John loves JavaScript";
console.log(text.slice(5, 10)); // loves
Classes are a way to capture under a single name a set of related properties (data) and methods (functions). The class is a blueprint for creating objects.
Lets create a class that represents a person:
// Class definition
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
console.log(Hello, my name is ${this.name} and I am ${this.age} years old.
);
}
}
var john = new Person("John", 30); // an object john is created
var jane = new Person("Jane", 25); // an object jane is created
john.speak(); // Hello, my name is John and I am 30 years old.
jane.speak(); // Hello, my name is Jane and I am 25 years old.
Lets create an array and object containing the same data:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
var point = new Point(5, 8);
var array = [5, 8];
console.log(point.x, point.y); // 5, 8
console.log(array); // [5, 8]
throw
- Throws an exception.
throw new Error("An error has occurred.");
The following syntax is used to handle exceptions:
try
- The try block contains the code that might throw an exception.catch
- The catch block contains the code that executes when an exception occurs.finally
- The finally block contains the code that executes regardless of whether or not an exception occurred.
try {
// code that might throw an exception
} catch (e) {
// code that executes when an exception occurs
} finally {
// code that executes regardless of whether or not an exception occurred
}
ReferenceError
- Thrown when a variable or function is not defined.TypeError
- Thrown when a value is not of the expected type.SyntaxError
- Thrown when a syntax error is encountered.URIError
- Thrown when an invalid URI is encountered.The DOM is a programming interface that allows you to access and manipulate the content of the web page.
<html>
tag.Let's look at the following HTML code:
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
In the example above:
<head>
tag contains the <title>
tag.<body>
tag contains the <h1>
tag.<h1>
tag contains the text Hello World!
.Now let us modify some properties of the <h1>
tag using JavaScript:
var h1 = document.querySelector("h1");
h1.style.color = "red";
h1.style.fontSize = "50px";
h1.style.textAlign = "center";
The following methods can be used to select elements from the DOM:
.querySelector()
- Returns the first element that matches a specified CSS selector(s) in the document..querySelectorAll()
- Returns a static NodeList containing all elements that match the specified CSS selector(s) in the document..getElementById()
- Returns the element that has the ID attribute with the specified value..getElementsByTagName()
- Returns a list of elements with the given tag name..getElementsByClassName()
- Returns a list of elements with the given class name.Here is an example of how to use the .getElementById()
method to change the background color to a gradient from light blue to dark blue.
var div = document.getElementById("container");
div.style.background = "linear-gradient(to right, #00ffff, #0000ff)";
Once selected, you can edit the content of the element using the following methods:
.innerHTML
- Sets or returns the HTML content (inner HTML) of an element..innerText
- Sets or returns the text content of an element..outerHTML
- Sets or returns the HTML content of an element, including the element itself..outerText
- Sets or returns the text content of an element, including the element itself.Let's append some text to a paragraph with id paragraph
:
var paragraph = document.getElementById("paragraph");
paragraph.innerHTML += "This text was appended using JavaScript.";
There are two types of events:
click
- Triggered when a user clicks on an element.change
- Triggered when a user changes the value of an element.mouseenter
- Triggered when the mouse pointer enters an element.mouseleave
- Triggered when the mouse pointer leaves an element.mousedown
- Triggered when the user presses a mouse button over an element.mouseup
- Triggered when the user releases a mouse button over an element.keydown
- Triggered when a user presses a keyboard key.keyup
- Triggered when a user releases a keyboard key.Let's add an event listener to the button with id button
:
var button = document.getElementById("button");
button.addEventListener("click", function() {
alert("The button was clicked!");
});
ES6+ features are JavaScript features that were added to the language in 2015. Those futures are widely considered to be a great improvement on the language.
...
- The spread operator is used to expand the elements of an array into a list of arguments.Let's take a look at a simple example:
var numbers = [1, 2, 3, 4, 5];
// Spread operator
var newNumbers = [...numbers, 6, 7, 8, 9, 10];
// Output
console.log(newNumbers); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Destructuring is a JavaScript feature that allows you to extract data from arrays and objects into distinct variables.
Let's take a look at a simple example:
var numbers = [1, 2, 3, 4, 5];
var [first, second, third] = numbers;
// Output
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3
Promise
- A promise is an object that represents the eventual result of an asynchronous operation.async
- The async keyword is used to declare functions that will execute asynchronously.await
- The await keyword is used to pause the execution of a function until a promise is resolved.Let's take a look at aexample:
async function getData() { // async function declaration
var response = await fetch("https://jsonplaceholder.typicode.com/users"); // awaitings the response of the fetch call
var data = await response.json(); // awaitings the response of the json call
console.log(data);
}
Template strings are a new type of string literal that allows embedded expressions.
In the example below we will use two variables in a template string:
var name = "John";
var age = 30;
var sentence = My name is ${name} and I am ${age} years old.
;
Object literals are another way (as opposed to the class syntax) to create objects. For a simple examples there is no difference between the two. When we start adding methods however, then each copy of an object created trough literal carries a copy of all the methods which leads to a memory waste.
In the example bleow we create a simple object called person
and add a method to it:
var person = {
firstName: "John",
lastName: "Doe",
id: 5566,
fullName: function() {
return this.firstName + " " + this.lastName;
}
};
person.fullName(); // "John Doe"
The for...of statement is used to iterate over iterable objects, arrays, and strings.
In the example below we will iterate over an array:
var array = [1, 2, 3, 4, 5];
for (var element of array) {
console.log(element);
}
Modules are a way to organize code into separate files.
In the example below we will create a module called person_module
and export a function called getFullName
:
module.exports = function getFullName(person) {
return person.firstName + " " + person.lastName;
};
Then we will import the module into another file:
var person_module = require("./person_module");
var person = {
firstName: "John",
lastName: "Doe"
};
var fullName = person_module.getFullName(person);
console.log(fullName); // "John Doe"
The ES6+ standard included new data structures such as Map, WeakMap, Set, and WeakSet.
Map
- A Map is a data structure that associates keys with values that will block the garbage collector from removing data it is referencing.WeakMap
- A WeakMap is a data structure that associates keys with values that will allow the garbage collector to remove data it is referencing.Set
- A Set is a data structure that associates unique values with keys that will block the garbage collector from removing data it is referencing.WeakSet
- A WeakSet is a data structure that associates unique values with keys that will allow the garbage collector to remove data it is referencing.Let's first demonstrate the difference between Map and WeakMap:
var map = new Map();
var weakMap = new WeakMap();
// we will now add some data to the map using a function
(function() {
var key = { extra: 5 }
var value = 10
map.set(key, value);
weakMap.set(key, value);
})();
// now let us see what will happen when we try to read the data
console.log(map); // Map { { extra: 5 } => 10 }
console.log(weakMap); // WeakMap { <items unknown=""> }
When iterating over a Map, be cautious. If you use a standard for
loop, you will get pairs of keys and values, but if you use forEach
, you will get values first, then keys!
const map = new Map([
['A', 1],
['B', 2],
]);
for (const [k, v] of map) {
console.log(k, v)
}
map.forEach((v, k) => {
console.log(v, k)
});
We can now subclass the built-in types such as Array, Date, and RegExp.
Let's take a look at an example where we extend the Array class with a new method:
class SpecialArray extends Array {
constructor(...args) {
super(...args);
}
front() {
return this[0];
}
}
arr = new SpecialArray(1, 2, 3);
console.log(arr.front()); // 1
TypeScript is a superset of JavaScript that compiles to plain JavaScript. It introduces many new features such as classes, interfaces, generics, and more.
Some of the advantages of using TypeScript are:
TypeScript has an integrated development environment that allows you to compile your code and see the errors that are generated.
tsc
- The TypeScript compiler is used to compile TypeScript code into JavaScript.tsc --init
- This command will create a tsconfig.json file in the current directory.tsc --watch
- This command will watch for changes in the source code and recompile the code when changes are detected.Let's say we have a TypeScript file called app.ts
and we want to compile it into a JavaScript file called app.js
:
tsc app.ts --outFile app.js
The above command will compile the TypeScript file into JavaScript and output the result into the file app.js
. You can now include the file in your HTML code since it's a plain old JavaScript.
Let's assume that we already built a JavaScript project and we now decided to convert it to TypeScript.
This file contains information used by the TypeScript compiler. A small example of the file is shown below:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src",
"lib": ["es5", "es6", "es2015.core", "es2015.promise", "es2015.iterable"]
},
"include": [
"src/**/*.ts"
]
}
Popular build tools include Webpack and Gulp. Webpack for example also uses configuration files to specify how to build the project. The configuration files are called webpack.config.js
and look something like this:
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' }
]
}
.js
files to .ts
.Package managers are used to install and manage dependencies. The chances are you won't be working with Vanilla JavaScript only. In fact you will probably be installing packages, libraries, and frameworks all the time. For that you will need a package manager.
NPM stands for "Node Package Manager," but don't be fooled by the term. React, SASS, Angular, Vue, and pretty much everything else can very certainly be installed and maintained using NPM.
To install the npm, download the installer from the official website.
To update NPM to the newest version, use:
npm install npm@latest -g
In order to set up a project with NPM, you should use the following command:
npm init
It will create a package.json
file in the root directory of your project. This file contains all important information about the project and its dependencies. Immediately after the command is executed, you will be prompted to enter the following information:
name
- The name of your project.version
- The version of your project.description
- A short description of your project.author
- The author of your project.license
- The license of your project.main
- The main file of your project.scripts
- A list of scripts that will be executed when you run npm run <script>
.dependencies
- A list of dependencies that will be installed when you run npm install
.devDependencies
- A list of devDependencies that will be installed when you run npm install
.You can also use the --yes
flag to skip the prompts.
The result of this process will look something like this:
{
"name": "my-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT",
"dependencies": {
"react": "16.3.2",
"react-dom": "16.3.2"
}
}
The most common way to install a package is to use the npm install
command with different flags:
npm install <package>
- This will install the package.npm install <package>@<version>
- This will install the package at the specified version.npm install <package>@<version> --save
- This will install the package at the specified version and save it to the dependencies
section of the package.json
file.npm install <package>@<version> --save-dev
- This will install the package at the specified version and save it to the devDependencies
section of the package.json
file.If you downloaded a project from the internet and that project already has a package.json
file, you can use the npm install
command to install the dependencies.
In order to list all installed packages, you can use the npm list
command:
npm list
- This will list all installed packages.npm list -g --depth=0
- This will list all global packages.npm update <package>
- This will update the package.npm update <package>@<version>
- This will update the package to the specified version.const
for immutable variables that won't be reassigned, improving clarity and preventing unintentional modifications. For variables that may change, use let
to clearly indicate their mutable nature.var
because its function-scoped behavior can lead to unpredictable results, especially in loops and conditionals. Stick with let
and const
for more reliable block-scoped declarations.data
or info
; instead, use names that reflect the variable’s purpose, like userProfile
or totalAmount
.this
, especially in callback functions and event handlers where you want to maintain the surrounding scope.forEach
, map
, filter
, and reduce
for a functional programming style, providing cleaner and more expressive ways to work with arrays.for...of
for array iteration for simplicity and readability, avoiding loop counter management. When iterating over objects, use Object.keys
, Object.values
, or Object.entries
for clear and functional property handling.? :
) for simple conditional expressions, making code compact and enhancing readability, especially for straightforward assignments or return statements.switch
statements for multiple conditions that depend on a single variable, improving readability. For more complex conditions, use if...else
statements to maintain clarity.try...catch
blocks in strategic places, such as network requests or JSON parsing, to maintain application stability..catch()
for Promises or try...catch
with async/await, preventing unhandled rejections and handling errors effectively.Promise.all
for concurrent operations and the AbortController API for cancellations, choosing synchronous or asynchronous code based on specific needs.