Skip to content

Setting up

History

  • Netscape wanted to make the web more interactive.They needed a scripting language that is easy to use and can be executed in the browser.Without needing a full page reload.
  • They hired Brendan Eich and he created the language in 10 days.The intense pressure was due to the fact that Microsoft was also developing a similar product called JScript.
  • They named it as LiveScript but later changed it to Javascript when Java was very popular to leverage the popularity of Java.
  • ECMA International standardized the language in 1997 and named it as ECMAScript(ES) due to compatibility issues between internet explorer and netscape.
  • Due to its rushed development,the language has some wierd behaviours initially which was later fixed with each new ECMAScript version.
  • For example,the typeof operator used to return “object” for null.
console.log(typeof null); // "object"

Setting up the runtime environment

  • Download runtime environment such as Node.js, Bun, Deno.Traditionally,Javascript was used only on the client side(in the browser).People used to open the console in the browser and write javascript code to test their ideas.Very few people used the core V8 engine outside the browser to write server side applications.

  • Node.js is the most popular runtime environment with vast ecosystem of libraries(npm).It was developed by Ryan Dahl in 2009, also developer of Deno.Built on the V8 JavaScript engine (the same engine used by Chrome), Node.js enables developers to use JavaScript to build server applications, command-line tools, APIs, and more.

  • Install any IDE such as VSCode.

Hello World in Node.js

  • Check if node is installed by running node -v in the terminal.
Terminal window
$ node -v
v18.16.0
  • Create a new folder for your project and open it in your IDE.Create a new file called index.js and save it in the folder.
index.js
console.log("Hello World!");
  • Open the terminal and run node index.js in the folder.Run the command to start the server.
Terminal window
$ node index.js
Hello World!

Variables and Constants

  • Variables are used to store data that can be changed during the execution of the program.
  • Constants are used to store data that cannot be changed during the execution of the program.
let variableName = "value";
const constantName = "value";
var variableName2 = "value";
// With Objects
const user = { name: "John", age: 25 };
user.name = "Jane"; // ✅ OK - Modifying property
user.age = 26; // ✅ OK - Modifying property
delete user.age; // ✅ OK - Deleting property
user.location = "NYC"; // ✅ OK - Adding new property
user = { name: "Bob" }; // ❌ ERROR - Cannot reassign const
// With Arrays
const numbers = [1, 2, 3];
numbers.push(4); // ✅ OK - Modifying array
numbers.pop(); // ✅ OK - Modifying array
numbers[0] = 10; // ✅ OK - Modifying element
numbers = [5, 6, 7]; // ❌ ERROR - Cannot reassign const
// With Sets (like our clients Set)
const clientSet = new Set();
clientSet.add("client1"); // ✅ OK - Modifying Set
clientSet.delete("client1"); // ✅ OK - Modifying Set
clientSet.clear(); // ✅ OK - Modifying Set
clientSet = new Set(); // ❌ ERROR - Cannot reassign const

Data Types

  • Javascript has two types of data types:Primitive and Non-Primitive.
  • Primitive data types are immutable(cannot be changed).
  • Non-Primitive data types are mutable(can be changed).
  • This categorisation reflects how JavaScript manages data in memory and how programs access this data. Primitive types are stored directly in memory, while non-primitive types store references to their data. For a deeper understanding, check out the MDN documentation on JavaScript data structures.

Primitive Data Types

  • Call by value: When a primitive data type is assigned to a variable, a copy of the value is created and stored in the new variable. Changes to one variable don’t affect the other since each has its own independent copy of the data.
// Example of call by value
let x = 10;
let y = x; // y gets a copy of x's value
y = 20; // modifying y doesn't affect x
console.log(x); // 10
console.log(y); // 20
  • String: Represents a sequence of characters.
  • Number: Represents numeric values.
  • BigInt: Represents numeric values that are too large to be represented by the Number type.
  • Boolean: Represents a boolean value.
  • Null: Represents a null value.
  • Undefined: Represents an undefined value.
  • Symbol: Used to create unique identifiers for objects.

Non-Primitive Data Types

  • Call by reference: When a non-primitive data type is assigned to a variable, the variable stores a reference (memory address) to the data rather than the actual data itself. This means multiple variables can point to the same data in memory, and modifying the data through one variable affects all references to that data.
// Example of call by reference
let arr1 = [1, 2, 3];
let arr2 = arr1; // arr2 references the same array as arr1
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4]
console.log(arr2); // [1, 2, 3, 4]
  • Array: Represents a collection of elements.
  • Object: Represents a collection of key-value pairs.
  • Function: Represents a function.

Type Conversion

  • Type conversion is the process of converting one data type to another.
  • When we are fetching data from a database or an API,or taking input from the user,we do not know whether the data is of the type we expect.Type conversion is used to handle such situations.
let a = 1;
let b = "2";
console.log(a + b); // "12"
// Here,Javascript automatically converts the number 1 to a string and concatenates it with the string "2".
let a = "124abc";
let num = Number(a);
console.log(num); // NaN
console.log(typeof num); // "number"
// Here,Javascript automatically converts the string "124abc" to a number.But since the string is not a valid number,it returns NaN.The typeof operator still returns "number".
let a = null;
console.log(a); // null
console.log(typeof a); // "object"
let num = Number(a);
console.log(num); // 0
console.log(typeof num); // "number"
// "25" => 25
// true => 1
// false => 0
// null => 0
// undefined => NaN
// "25abc" => NaN
// "abc" => NaN
// {} => NaN
// [] => 0
// [1,2,3] => NaN
// (function(){}) => NaN
// Symbol => NaN
// Boolean => true or false
// "true" => true
// "false" => true
// "" => false

Operator Precedence

  • Operator precedence determines the order in which operators are evaluated in an expression.
  • For example,in the expression 2 + 3 * 4,the multiplication operator * has higher precedence than the addition operator +.So,it is evaluated first.
// Examples
console.log(2 + 3 * 4); // 14 (multiplication happens first)
console.log((2 + 3) * 4); // 20 (parentheses override precedence)
console.log(5 > 3 && 2 < 4); // true (comparison before logical AND)

For a complete reference, visit MDN’s Operator Precedence documentation.

Prefix and Postfix Operators

  • Prefix operators are operators that are placed before the operand.
  • Postfix operators are operators that are placed after the operand.
let a = 1;
console.log(++a); // 2
console.log(a); // 2
console.log(a++); // 2
console.log(a); // 3
  • To learn more about prefix and postfix operators,visit MDN.

Comparison Operators

  • Comparison operators are used to compare two values.
  • The result of a comparison is a boolean value.
console.log(2 == "2"); // true
console.log(2 === "2"); // false
console.log(2 != "2"); // false
console.log(2 !== "2"); // true
console.log(null > 0); // false
console.log(null == 0); // false
console.log(null >= 0); // true
// The reason for the above behaviour is that the comparison operator converts null to a number,treating it as 0.That is why null >= 0 is true and null > 0 is false.Equality check == does not convert null to a number.That is why null == 0 is false.
// To avoid such confusion,it is recommended to use the strict equality operator ===.Write code in a way that does not rely on type conversion.Clean code is always preferred.

Stack and Heap Memory

  • Stack memory is used for primitive data types.
  • Heap memory is used for non-primitive data types.

Stack Memory

  • The stack memory in JavaScript operates on a Last-In-First-Out (LIFO) principle:
  • Each primitive variable gets pushed onto the stack
  • Each value has its own space in memory
  • Variables are removed in reverse order of their addition
  • Stack memory is automatically managed
  • Perfect for primitive data types (numbers, strings, booleans)
JavaScript Call Stack
═══════════════════════════════════
Function Returns
⬆️
┌────────────────────┐ │
│ Function C │ │
│ │ │
├────────────────────┤ │
│ Function B │ │
│ │ │
├────────────────────┤ │
│ Function A │ │
│ │ │
├────────────────────┤ │
│ Main() │ │
└────────────────────┘ │
Call Stack │
Function Calls
╔══════════════════════════════════════╗
║ Execution Order ║
╠══════════════════════════════════════╣
║ 1. Main() calls Function A ⬇️ ║
║ 2. Function A calls B ⬇️ ║
║ 3. Function B calls C ⬇️ ║
║ 4. C completes, returns to B ⬆️ ║
║ 5. B completes, returns to A ⬆️ ║
║ 6. A completes, returns to Main ⬆️ ║
╚══════════════════════════════════════╝

Heap Memory

  • The heap memory in JavaScript is used for non-primitive data types.
  • Objects are stored in the heap memory.
  • Variables hold references to the objects in the heap.
  • Multiple references can point to the same object.
  • Memory is cleaned by the garbage collector.
JavaScript Heap Memory
═══════════════════════════════════
Stack (References) Heap (Objects)
┌──────────────────┐ ╔════════════════════╗
│ │ ║ Object 1 ║
│ person1 ─────────┼─────→║ { ║
│ │ ║ name: "Alice", ║
│ │ ║ age: 25 ║
│ person2 ─────────┼─┐ ║ } ║
│ │ │ ╚════════════════════╝
└──────────────────┘ │
│ ╔════════════════════╗
└────→║ Object 2 ║
║ { ║
║ name: "Bob", ║
║ age: 30 ║
║ } ║
╚════════════════════╝
╔════════════════════════════════════════════════════╗
║ Key Characteristics ║
╠════════════════════════════════════════════════════╣
║ • Objects are stored in heap memory ║
║ • Variables hold references (pointers) to objects ║
║ • Multiple references can point to same object ║
║ • Memory is cleaned by garbage collector ║
║ • No guaranteed order of storage ║
╚════════════════════════════════════════════════════╝
Example Code:
────────────────────────────────────────────────────
let person1 = { name: "Alice", age: 25 };
let person2 = { name: "Bob", age: 30 };
// person1 and person2 store references to
// their respective objects in the heap

String Interpolation

  • String interpolation is the process of embedding variables or expressions within a string.
  • In older versions of Javascript,we used to use the + operator to concatenate strings.
let name = "Alice";
console.log("Hello " + name); // "Hello Alice"
  • In modern versions of Javascript,we use template literals to achieve string interpolation.
let name = "Alice";
console.log(`Hello ${name}`); // "Hello Alice"

String Methods

  • String methods are functions that can be used to manipulate strings.
let name = "Alice";
console.log(name.toUpperCase()); // "ALICE"
console.log(name.toLowerCase()); // "alice"
console.log(name.length); // 5
console.log(name.slice(1, 3)); // "li"
console.log(name.replace("A", "B")); // "Blic"
console.log(name.includes("A")); // true
console.log(name.indexOf("A")); // 0
console.log(name.charAt(0)); // "A"
console.log(name.split("")); // ["A", "l", "i", "c", "e"]
console.log(name.trim()); // "Alice"
console.log(name.padStart(10, "X")); // "XXXXXAlice"
console.log(name.padEnd(10, "X")); // "AliceXXXXX"
console.log(name.repeat(3)); // "AliceAliceAlice"
  • To learn more about string methods,open the console in your browser and type String.prototype.You will see a list of methods that can be used with strings.Since all strings are objects in Javascript,they have methods associated with them.Visit MDN for more information.

Numbers

  • Numbers in Javascript are of type number.
  • We can use the Number object to create numbers.
let num = new Number(10);
console.log(num); // 10
console.log(typeof num); // "object"
// We can also use the Number constructor to convert a string to a number.
let num = Number("10");
console.log(num); // 10
console.log(typeof num); // "number"
// Methods of the Number object
console.log(num.toString()); // "10"
console.log(num.toFixed(2)); // "10.00"
console.log(num.toPrecision(3)); // "10.0"
console.log(num.toExponential(2)); // "1.00e+1"
console.log(num.toLocaleString()); // "10"
console.log(num.toPrecision(3)); // "10.0"
Number.MAX_VALUE; // 1.7976931348623157e+308
Number.MIN_VALUE; // 5e-324
  • To learn more about the Number object,visit MDN.

Math Object

  • The Math object in Javascript provides a set of methods for performing mathematical operations.
console.log(Math.abs(-10)); // 10
console.log(Math.ceil(1.1)); // 2
console.log(Math.floor(1.9)); // 1
console.log(Math.round(1.5)); // 2
console.log(Math.max(1, 2, 3)); // 3
console.log(Math.min(1, 2, 3)); // 1
console.log(Math.random()); // 0.12345678901234567 (random number between 0 and 1)
console.log(Math.pow(2, 3)); // 8
console.log(Math.sqrt(16)); // 4
console.log(Math.cbrt(8)); // 2
console.log(Math.sin(Math.PI / 2)); // 1
console.log(Math.cos(0)); // 1
console.log(Math.tan(Math.PI / 4)); // 1
  • To learn more about the Math object,visit MDN.

Date and Time

  • The Date object in Javascript provides a set of methods for working with dates and times.
let date = new Date(); // New keyword is used to create a new Date object.
console.log(date); // "Day Month Date Year Hours:Minutes:Seconds GMT+Timezone"
// Methods of the Date object
console.log(date.getFullYear()); // 2024
console.log(date.getMonth()); // 10 (0-11)
console.log(date.getDate()); // 15
console.log(date.getHours()); // 10
console.log(date.getMinutes()); // 10
console.log(date.getSeconds()); // 10
console.log(date.getDay()); // 3 (0-6)
console.log(date.getTime()); // 1726358410000 (milliseconds since January 1, 1970)
console.log(date.toLocaleString()); // "Day Month Date Year Hours:Minutes:Seconds GMT+Timezone"
console.log(date.toLocaleDateString()); // "Day Month Date Year"
console.log(date.toLocaleTimeString()); // "Hours:Minutes:Seconds"
// We can also use the toLocaleString method to format the date.
console.log(date.toLocaleString('default', {month: 'long'})); // "Day Month Date Year"
  • To learn more about the Date object,visit MDN.

Symbols in JavaScript

Symbols create unique identifiers that help prevent naming conflicts.

  • Here is an example of how Symbols can be used to create private properties of an object.
  • We developed a game and we want to store the score of the player in a private property.We can use a Symbol to create a unique key for the score property.
  • Symbols are not enumerable/iterable and are not accessible using regular object inspection.
  • If another developer wants to add a new property with the same name as the Symbol,it will not override the existing property.
// Create a Symbol for tracking game score
const scoreKey = Symbol('score');
const gamePlayer = {
name: 'Player 1',
level: 1,
[scoreKey]: 0, // "Private" score counter using Symbol
// Methods to work with the score
addPoints(points) {
this[scoreKey] += points;
},
getScore() {
return this[scoreKey];
}
};
// Using the game player
gamePlayer.addPoints(100);
console.log(gamePlayer.getScore()); // 100
// Regular object inspection won't show the score
console.log(Object.keys(gamePlayer)); // ['name', 'level']
// Another developer can't accidentally override our score system
gamePlayer.score = 999; // This creates a different property
console.log(gamePlayer.score); // 999
console.log(gamePlayer.getScore()); // Still 100

This shows how Symbols can help create properties that won’t conflict with other property names, useful when building reusable code or libraries.