Js Basic
Js Basic
In Python, a block of code is defined by its indentation level. In JavaScript, code blocks
for if statements, loops, and functions are wrapped in curly braces {}
For Example: A Basic if statement
JS
if (name == "Alice") {
[Link]("You are Alice!");
// [Link] is JS equivalent of python's print
}
JS uses ; to end a statement but nowadays, these are optional but still a good practice for code
readability
Variables
let
Generally the standard way.
It is block-scoped which means it can only be accessed in the {} it is defined as it does
not create a property on the global object
Reassigning is allowed, Redeclaration is not
It is not hoisted, thus accessing a variable before declaration throws a reference error
making it easy to catch bugs early
let creates a new binding for each iteration
var
The legacy way
It is function scope which means it can be accessed throughout the function i.e. in all
the {} inside of the function
It creates a property on global object
It is hoisted at the top of its scope, which means it is initialized at the top of the scope
with value undefined
Allows both redeclaration and reassigning
var does not create a new binding for each iteration, thus unexpected behavior. Ex:
for (var i = 0; i < 3; i++) {setTimeout(() => [Link](i), 100);}
Outputs : 3 3 3
Constants
const is used to assign a new constant, constants cant be reassigned but mutated.
This means that you cannot change the memory address it is pointing to but you can change the
value in the memory address
For example: You cannot change the array a const is pointing to but change the array itself
TDZ
Both let and const are put in a temporal-dead-zone at the start of the code block till the
declaration statement, this is called hoisting, when here they can be accessed but would have
value undefined
Datatypes
JS is a dynamically typed language and you dona't need to declare the datatype of the variable
along with value.
Primitive Datatypes
A primitive datatype is a simple, immutable piece of data—it doesn't have its own methods or
properties in the way an object does. There are seven primitive types
String :
Number : Can store both int and float
Boolean
null : It represents the intentional absence of any object value
undefined : A variable that has been declared but has not yet been assigned a value
Symbol : Creates unique identifiers. Each Symbol is guaranteed to be unique, even if created
with the same description.
BigInt : Used to create numbers greater than allowed by Number
Use the datatype name as the function name for a function to convert datatypes. Example:
Number("31") //returns 31
JS
const name = "yash";
let greet_message = `Hi $(name)!`;
// Note the use of `` bracketts and not the regular quotes
Objects
An object is a collection of properties, and a property is an association between a key (or name)
and a value. Arrays, dates, and functions are all special types of objects in JavaScript.
Operators
Only uncommon are mentioned here
Arithmetic Operators
Remainder/ Modulo %
Increment by 1 ++ (Similarly, -- )
Bitwise Operators
Bitwise operators don't operate on the number but its binary representation
All bitwise ops in JS coerce numbers to 32‑bit signed integers. Results wrap at 32 bits.
x >>> n
This shifts the bits n places to the right, deleting the overflowing bits and adding 0 to the left
bits. This returns a 32-bit signed integer. This is useful for:
x >>> 0 :
Converting negative signed numbers to unsigned numbers (For functions or operations
that expect an unsigned number as input, Ex: Hashing Algorithms).
Bitwise it performs no manipulation just tells the computer to treat it as an unsigned
number from now.
That is why negative numbers appear as large positive numbers, nothing in data is
changed just they are now read as unsigned numbers and as the leftmost bit is 1 they
appear as large positive numbers
x >>> n :
Fast division by powers of 2
It is basically [Link](x / 2^n)
and others.
x >> n :
This shifts the bits n places to the right, discarding the right side bits and adding 0's to the
left if the number was positive and 1's if the number was negative. This returns a 32-bit
unsigned integer
x << n :
This shifts the bits n places to the left, discarding the left side bits and adding 0's to the
right. This returns a 32-bit signed integer
Masking with &
Masking is the process of using a bitwise operator (usually & ) to isolate, remove, or check for
specific bits in a number. It acts like a stencil to either block or reveal parts of the binary data.
Example: Extracting a Color Channel Goal: Get the green value ( 99 ) from a color represented
as 0xFF9933 .
The Number (in binary): 11111111 10011001 00110011
Shift to position the data: Shift right by 8 to move the green value to the end.
JS
let shifted = 0xFF9933 >> 8;
// Result of shifted: 0b1111111110011001 (value is 0xFF99)
Apply the Mask: Use & 0xFF to clear everything except the last 8 bits.
JS
let green = shifted & 0xFF;
// Calculation
// ... 11111111 10011001 (shifted value)
// & ... 00000000 11111111 (the mask, 0xFF)
// ---------------------------------------
// ... 00000000 10011001 (final result)
Final Result: The result is 0b10011001 , which is 153 in decimal ( 0x99 in hex). The mask
successfully isolated the green value.
BitMasking
Here, we would use 1 variable to represent a collection of 8 boolean variables and then edit that
1 variable to change the individual boolean variables
Example ->
JS
// Lets say the first switch has value 1
const switch_1 = 1 << 0; // 00000001
// Lets say the second switch has value 0
const switch_2 = 0 << 1; // 00000000
// Lets say the third switch has value 1
const switch_3 = 1 << 2; // 00000100
// Similary creating 5 more switches
//Adding all the switches in switch_matrix using or, so that all the 1's will change
the 0's of switch_matrix to 1
switch_matrix = switch_matrix | switch_1
switch_matrix = switch_matrix | switch_2
switch_matrix = switch_matrix | switch_3
//Similarly do with the others
Calculation
....0...
& ....1...
----------
....1..
JS
// Turning the first switch off
switch_matrix = switch_matrix & (~(1<<0));
Calculation
Assignment Operators
Operator Equivalent to
x = y x = y
x += y x = x + y
x -= y x = x - y
x *= y x = x * y
x /= y x = x / y
x %= y x = x % y
x **= y x = x ** y
x &= y x = x & y
x \|= y x = x \| y
x ^= y x = x ^ y
x <<= y x = x << y
x >>= y x = x >> y
x >>>= y x = x >>> y
x &&= y x = x && y
x \|= y x = x \| y
x ??= y x = x ?? y
Comparison Operators (Focus on Equality)
Control Flow
Conditional Statements
The code flow goes from if -> else if -> else if -> ... -> else
JS
let age = 20;
Switch
The switch statement checks a value and executes code blocks based on matching case . The
break keyword is crucial; without it, the code will "fall through" and execute the next case as
well.
JS
let day = 3;
let dayName;
switch (day) {
case 1:
dayName = "Monday";
break;
case 2:
dayName = "Tuesday";
break;
case 3:
dayName = "Wednesday";
break;
// ... other days
default:
dayName = "Invalid day";
}
[Link](dayName); // "Wednesday"
while loop
JS
// Syntax //while (condition) {code};
let count = 1; // 1. Initializer
while (count <= 5) { // 2. Condition
[Link](`The count is ${count}`);
count++; // 3. Incrementer
}
for loop
JS
// Syntax // for (Initializer;Condition;Incrementer)
for (let i = 0; i < 5; i++) {
[Link](`The number is ${i}`);
}
JS
const colors = ["red", "green", "blue"];
try catch
JS
try {
// Code that might throw an error
riskyOperation();
} catch (error) {
// Code that runs if an error was thrown
[Link](`An error happened: ${[Link]}`);
}
Functions
Entire functions in javascript are in hoisted, which means they can be called before declaration
Regular Syntax ->
JS
function functionName(parameter1, parameter2) {
// code to be executed
return 0;
}
JS
const variableName = (parameter1, parameter2) => {
// code to be executed
return 0;
};
For arrow functions, if your function is just one line that returns a value, you can omit the {} and
the return keyword.
JS
const add = (a, b) => a + b; // Shorter way to write a return
Scope
Global
For each javascript realm on creation a new ordinary object - global object is created, this is
then populated with all the built-ins ( Array , Json , parselnt etc.). Every script running inside that
realm sees that same object as its outermost scope. Every new object (variable, function etc.) is
appended to this global object.
Examples of realm:
Concrete examples:
One browser tab ⇒ one realm. (referred to as window )
One <iframe> ⇒ its own realm (so its own global object).
One Web Worker ⇒ its own realm.
One [Link] process ⇒ its own realm.
iframes have their own realm but Inside an iframe’s JavaScript, the identifier parent is
automatically provided by the browser and is a direct reference to the global object of the
parent window or frame, so any global variables stored there can be read or written via
[Link]
JavaScript can only reach another realm’s global object if the two realms satisfy the same-
origin policy which means they both have the same protocol, host and port.
Each browser tab, is one realm which has one global object -> window , this contains
Your Global Code: Any variables created with var and any function declarations in the
global scope become properties of the window object.
var myVar = 10; is the same as [Link] = 10;
JavaScript Built-ins: The standard objects and functions that are part of the core
JavaScript language.
Data Types & Constructors: Object , Array , String , Number , Boolean .
Utility Objects: JSON (for parsing and stringifying data), Math (for mathematical
operations).
Global Functions: parseInt() , setTimeout() , console , etc.
Browser APIs (Application Programming Interfaces): These are the special tools the
browser provides to interact with the webpage and the user's environment.
DOM (Document Object Model): The document object is the most famous property of
window . It's your gateway to selecting and manipulating every HTML element on the
page
Event Handling: Tools to listen for user actions, like addEventListener .
Browser Information: navigator (information about the browser itself), location
(information about the current URL)
Networking: fetch() for making API requests to servers
Function Scope
When any function is invoked in JavaScript, a new scope is created for that specific execution.
All variables declared inside this function are local to that scope and are not accessible from the
outside. Historically, this was the primary way to create private, encapsulated state in
JavaScript. The var keyword is the quintessential example of a function-scoped variable.
The mechanism behind this is the creation of a new Execution Context for each function call.
This context contains a Lexical Environment, an internal data structure that holds the identifiers
(variables, functions) defined within that function.
Privacy: It's a one-way mirror; code inside the function can "see out" to the containing
(parent) scopes, all the way up to the Global Scope, but code outside cannot "see in". This
lookup process is known as the scope chain.
Hoisting: Declarations using var are hoisted to the top of their containing function scope
and are initialized with the value undefined . This means they can be accessed before their
textual declaration without a ReferenceError , though their value will be undefined .
Closures: Function scope is the basis for closures. A closure is formed when a function is
defined inside another function, allowing the inner function to maintain access to its outer
function's Lexical Environment (its variables and parameters) even after the outer function
has finished executing.
Example of a Closure:
JS
function createCounter() {
let count = 0; // 'count' is in the function scope of createCounter
Block Scope
Introduced in ECMAScript 2015 (ES6), block scope provides a more granular way to declare
variables that are only accessible within a specific block. A block is defined by any pair of curly
braces {} , such as in if , for , while statements, or even standalone blocks. The let and const
keywords are used to declare block-scoped variables.
This was created to solve common issues with var where variables would "leak" out of loops
and conditionals, leading to bugs.
Granularity: It allows developers to constrain the life of a variable to the smallest possible
area where it is needed. In a for loop declared with let , a new lexical environment and a
new binding for the loop variable are created for each iteration.
Temporal Dead Zone (TDZ): While let and const declarations are also hoisted to the top of
their block, they are not initialized. The period from the start of the block until the
declaration statement is executed is called the Temporal Dead Zone. Attempting to access
the variable within the TDZ results in a ReferenceError . This prevents bugs that arise from
using a variable before it has been declared and assigned a value.
No Re-declaration: Unlike var , you cannot re-declare the same variable using let or const
within the same block scope
Example of TDZ and Block Scope:
JS
function process(items) {
// 'i' is in the TDZ here
// [Link](i); // ReferenceError: Cannot access 'i' before initialization
Array
Defining Array
JS
// An empty array
let emptyArray = [];
// An array of numbers
let scores = [98, 85, 91, 78];
JS
let fruits = ["apple", "banana", "cherry"];
// Accessing
[Link](fruits[0]); // "apple"
[Link](fruits[[Link] - 1]); // "cherry"
// Modifying
fruits[1] = "blueberry";
[Link](fruits); // ["apple", "blueberry", "cherry"]
Working of sort() :
sort takes two values, from array and then passes them to the compare function, the functions
return value determines the correct order, the smaller the value the smaller the index of the
element
A simple ascending function is ->
[Link]( (a,b) => a-b);
How it works?
Say, The original array is [40, 100, 1, 5, 25, 10]
1. Start with the first two elements, 40 and 100. The comparison (a=40, b=100) results in 40 -
100 = -60. Because the result is negative, 40 is placed before 100. The current sorted
portion is [40, 100]
2. Next, process the number 1. It is first compared with 100 (a=1, b=100), which results in 1 -
100 = -99 (negative), so 1 must come before 100. It is then compared with 40 (a=1, b=40),
which results in 1 - 40 = -39 (negative), so 1 must also come before 40. Having reached the
start of the sorted portion, 1 is placed at the beginning. The current sorted portion is [1,
40, 100]
3. Process the number 5. It is compared with 100 (negative result), then 40 (negative result).
The comparison with 1 (a=5, b=1) results in 5 - 1 = 4. Because this is a positive result, the
algorithm knows 5 must come after 1 and stops. The current sorted portion is [1, 5, 40,
100]
4. Process the number 25. It is compared with 100 (negative) and 40 (negative). The
comparison with 5 (a=25, b=5) gives a positive result (25 - 5 = 20), so 25 is placed after 5.
The current sorted portion is [1, 5, 25, 40, 100]
5. Process the final number, 10. It is compared with 100 (negative), 40 (negative), and 25
(negative). The comparison with 5 (a=10, b=5) gives a positive result (10 - 5 = 5), so 10 is
placed after 5. The current sorted portion is [1, 5, 10, 25, 40, 100]
Non-Mutating Methods (Returns a new array or value)
Method Description
[Link](item => {}) Executes a provided function once for each array element. It
doesn't return anything ( undefined ).
[Link](item => {}) Creates a new array populated with the results of calling a
provided function on every element.
Method Description
[Link](item => {}) Creates a new array with all elements that pass the test
implemented by the provided function (i.e., the callback
returns true ).
[Link](item => {}) Returns the first element in the array that satisfies the
provided testing function. Otherwise undefined is returned.
[Link](item => {}) Tests whether all elements in the array pass the test.
Returns true or false .
[Link](item => {}) Tests whether at least one element in the array passes the
test. Returns true or false .
[Link]((acc, item, index?, - Iterates over the array and reduces it to a single value.
array?) => {}, initialValue) - acc → accumulator (result carried over) (required)
- item → current element (required)
- index → index of current element (optional)
- array → the original array (optional)
- initialValue → starting value (optional, but safer to
provide)
Additional Notes->
Arrays are passed by reference and not by value, this means if you assign the array to a new
variable you are just copying the pointer to the new variable.
JS
let arrA = [1, 2];
let arrB = arrA; // arrB points to the same array
[Link](3);
[Link](arrA); // [1, 2, 3] <-- The original was changed!
Spread Syntax is the equivalent of Python's * operator for unpacking iterable and it's extremely
useful.
JS
let parts = ["shoulders", "knees"];
let body = ["head", ... parts, "toes"]; // ["head", "shoulders", "knees", "toes"]
As we know that simply assigning the existing pointer variable to another variables just creates a
copy of the pointer and not the array itself to make a true copy(shallow) just unpack the array
into another array with spread-syntax
JS
let colors = ["red", "blue", "green"];
let paint = [ ... colors];
This is still not a 1:1 copy as nested objects are still just pointers
Destructing Assignment -> Similar to python's unpacking, here ... is used to unpack, think of
this as a clean way to unpack values from an array into distinct variables
Objects
These are similar to python dictionaries, and hold key-value pairs
JS
// An empty object
const car = {};
JS
// Accessing a value
[Link]([Link]); // "Alice"
// Modifying a value
[Link] = 31;
[Link]([Link]); // 31
JS
delete [Link];
[Link](user); // The isLoggedIn property is now gone
JS
const personClassic = {
name: "Alice",
greet: function() { // The value is an anonymous function
[Link](`Hello, my name is ${[Link]}`);
}
};
JS
const personModern = {
name: "Alice",
greet() {
[Link](`Hello, my name is ${[Link]}`);
}
};
[Link](obj) : Returns an array of the object's keys (as strings). You can then use array
methods on it. This is the most common and useful method.
[Link](obj) : Returns an array of the object's values.
[Link](obj) : Returns an array of [key, value] pairs. Very powerful.
JS
const car = { brand: "Ford", model: "Mustang" };
Note ->
This is also passed by reference, also thus similar to array to make a shallow copy use ...
Prototypical Inheritance
Almost every object in JavaScript has a hidden, internal property that links to another
object. This "master" object is its prototype.
When you try to access a property on an object, if JavaScript can't find it on the object itself,
it looks at the object's prototype. If it's not there, it looks at the prototype's prototype, and
so on. This is called the prototype chain.
All plain objects you create link to a master object called [Link] . This master object is
where methods like .toString() , .hasOwnProperty() , etc., are stored. This system is how
JavaScript implements inheritance.
// Using the getter (looks like a property, but runs the function)
[Link]([Link]); // "John Doe"
// Using the setter (looks like assigning a property, but runs the function)
[Link] = "Jane Smith";
[Link]([Link]); // "Jane"
[Link]([Link]); // "Smith"
DOM
The browser organizes the page into a tree, this is called DOM
Example:
HTML
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Welcome!</h1>
<p>This is my website.</p>
</body>
</html>
DOM Tree
document
└── html
├── head
│ └── title
└── body
├── h1
└── p
DOM Selection
getElementByID() ->
It looks for the one and only element with a specific id .
Example-> const pageTitle = [Link]('main-title');
querySelector() ->
This method lets you select elements using CSS selector syntax (the same selectors
you'd use in a CSS file)
To select by ID: [Link]('#id-name')
To select by class: [Link]('.class-name')
To select by tag: [Link]('tag-name')
One important thing to know is that querySelector() always returns only the first
element it finds that matches the selector.
Both of these return the entire tag and not just the content, to just get specific parts either
use regex or just one of the following attributes for the querySelector or getElementById object
For a <div> tag: The object would represent the container itself and have properties like:
.children : A list of all the HTML elements nested inside the div.
.innerHTML : To see or completely replace the content inside the div.
To edit a part, just select it using these and use the assignment operator =
Also if no object with the required id/ class etc. is found then null object is returned
Adding elements
The process for adding a new element to the page has three main steps:
1. Create: Create a new, empty element in JavaScript's memory. (Gathering your ingredient).
2. Configure: Set its content, classes, styles, and other attributes. (Prepping and seasoning
the ingredient).
3. Append: Choose a location on the page and place the new element there. (Adding the
ingredient to the dish).
JS
// Let's configure our new paragraph from Step 1
[Link] = 'This paragraph was created by JavaScript!';
JS
// First, we need to select the parent element
const container = [Link]('#container');
Removing Element
JS
// Let's say we want to remove the paragraph we just added
const paragraphToRemove = [Link]('#p-1');
Events
This is a three step process ->
This is the modern and most common way to handle events. It looks like this:
[Link]('eventTypea', functionToRun);
Example ->
JS
// Part 1: Select the elements we need to work with
const pageTitle = [Link]('#main-title');
const myButton = [Link]('#my-button');
This keyword
Previously, this keyword was used inside of objects to create methods, where would want to
refer to the encompassing object itself.
Inside a function, this keyword refers to the global object, generally window
JS
function showThis() {
[Link](this === window); //true
}
showThis();