JavaScript - robbiehume/CS-Notes GitHub Wiki
Related Wiki links
Useful links
- Different ways to loop through array in JS
- JS vs jQuery vs Ajax
- JavaScript Overview (MDN)
- Complete JavaScript handbook (free codecamp)
Useful sites
Look into:
General notes
;
)
Semicolons (- Semicolons are technically only needed before a line that starts with
[
,(
,/
,+
,-
or IIFEs
let
vs var
: link
- Other link showing loop use case
- The main difference is scoping rules. Variables declared by
var
keyword are scoped to the immediate function body (hence the function scope) whilelet
variables are scoped to the immediate enclosing block denoted by{ }
(hence the block scope)
Asynchronous
Overview
- Synchronous vs Asynchronous JavaScript – Call Stack, Promises, and More
- JavaScript is synchronous by default, but it is possible to asynchronous tasks
- We can classify most asynchronous JavaScript operations with two primary triggers:
- Browser API/Web API events or functions: these include methods like
setTimeout
, or event handlers like click, mouse over, scroll, and many more - Promises: unique JavaScript object that allows us to perform asynchronous operations
- Browser API/Web API events or functions: these include methods like
- Browser APIs like
setTimeout
and event handlers rely oncallback
functions. A callback function executes when an asynchronous operation completes - The event loop manages the call stack and receives browser APIs / callback function calls
- There is also a special
callback queue
/task queue
that holds tasks to run once the call stack is empty - For promises, the JavaScript engine doesn't use the
callback queue
; it uses another special queue called thejob queue
- Items in the
job queue
are given priority over thecallback queue
items - Order of precedence (first to last): call stack, promises, browser APIs (async callbacks)
Promises
- Guide to JS promises (free code camp)
- In JavaScript, promises are special objects that help you perform asynchronous operations
- You can create a promise using the
Promise
constructor, which takes anexecutor
function - In the executor function, you define what you want to do when a promise returns successfully or when it throws an error
- You can do that by calling the
resolve
andreject
methods, respectively
- You can do that by calling the
- Example:
const promise = new Promise((resolve, reject) => resolve('I am a resolved promise'))
- After the promise is executed, we can handle the result using the
.then()
method and any errors with the.catch()
methodpromise.then(result => console.log(result))
- For promises, the JavaScript engine doesn't use the same
callback queue
we have seen earlier for browser APIs. It uses another special queue called thejob queue
Job Queue
- Every time a promise occurs in the code, the executor function gets into the job queue
- The event loop works, as usual, to look into the queues but gives priority to the
job queue
items over thecallback queue
items when the stack is free - The item in the callback queue is called a
macro task
, whereas the item in the job queue is called amicro task
await
await
is usually used to unwrap promises by passing aPromise
as the expression- Using
await
pauses the execution of its surroundingasync
function until the promise is settled (that is, fulfilled or rejected)
jQuery
- jQuery Examples
- The standalone $ stands for jQuery. Ex:
$.each()
is equivalent tojQuery.each()
- Side note:
$.each()
is not the same as$(selector).each()
; source
- Side note:
- There is also the $() method used to get HTML elements
$("p")
: get all <p> elements$("#test")
: get all elements with id="test"$(".test")
: get all elements with class="test"$(this)
: get the current HTML element
Angular vs React vs Vue
Syntax Notes
||
and??
operator in variable definition: link; link2||
(logical OR):- Returns the first truthy value
- If the left-hand side is falsy (like
0
,''
,false
,null
, orundefined
), it returns the right-hand side - Ex:
const value = '' || 'default'
// Since '' is falsy, it outputs 'default'
&&
(nullish coalescing):- Returns the first non-null / undefined value
- Only
null
andundefined
trigger the fallback to the right-hand side - Ex:
const value = '' ?? 'default'
// Since '' is neither null or undefined, it outputs '', even though it's falsy
- The main difference is that
||
will treat all falsy values as if they need the fallback, whereas??
only applies the fallback if the value isnull
orundefined
; it is more restrictive
this
Keyword
- Understanding
this
is crucial for working with object methods, event handlers, and callbacks in JavaScript- The
bind
method can be used to ensurethis
has the correct context
- The
- The value of
this
is determined by how a function is called, not where it is defined (except for arrow functions)- For arrow functions, the value of
this
is determined by where it's defined - Example:
-
const user = { name: 'Alice', greet() { console.log(`Hello, ${this.name}`); } }; user.greet(); // "Hello, Alice" const greet = user.greet; greet(); // "Hello, undefined" (or "Hello, window.name" in non-strict mode)
-
- For arrow functions, the value of
- You can explicitly bind
this
usingbind
,call
, orapply
-
const greet = user.greet.bind(user); greet(); // "Hello, Alice"
-
this
in different contexts:- In the global execution context (outside of any function), this refers to the global object
- When a method is called as a property of an object, this refers to the object itself
- In event handlers, this typically refers to the element that fired the event, but in modern JavaScript frameworks, this behavior can be customized
- Deciding how you want use
this
depends on which type you use- Traditional function: the value of
this
depends on how the function is called-
function Person() { this.age = 0; setInterval(function() { this.age++; // `this` refers to the global object, not the `Person` instance console.log(this.age); }, 1000); } const p = new Person(); // `this` inside setInterval does not refer to `p`
-
- Arrow function: the value of this is inherited from the outer scope (lexical binding)
-
function Person() { this.age = 0; setInterval(() => { this.age++; // `this` refers to the instance of `Person` console.log(this.age); }, 1000); } const p = new Person(); // `this` inside the arrow function refers to `p`
-
- Traditional function: the value of
Function Definitions
Anonymous functions
- An anonymous function is simply a function without a name
- They're often used in places where a function is passed as an argument to another function, such as callbacks, event handler, or function expressions
- Example:
-
setTimeout(function() { console.log('This is an anonymous function'); }, 1000);
-
Comparison table
-
Feature Function Declaration Function Expression Arrow Function Syntax function name() {}
const name = function() {}
const name = () => {}
Hoisting Yes (can be called before defined) No (must be defined before use) No (must be defined before use) this
BindingHas its own this
Has its own this
Inherits this
from the surrounding scopeAnonymous No (must have a name) Can be anonymous or named Always anonymous arguments
objectYes Yes No (use rest parameters ...args
instead)Pros Clear, named functions, hoisted More flexible (anonymous/named), context-aware Concise syntax, easy handling of this
, good for callbacksCons Verbose for simple functions, this
can be confusingNot hoisted, this
binding can be trickyLack of own this
andarguments
, less readable for complex logicUse Cases Named functions, reusable logic Callback functions, passing functions around Short callbacks, avoiding this
issues
Function declaration:
- The most common way to define a function; uses the
function
keyword - Hoisting: function declarations are hoisted to the top of their scope. This means you can call the function before it is defined in the code
- When to use function declarations:
- Top-level functions: when you need functions that should be available throughout a scope (e.g., utility functions)
- Consistency: function declarations are straightforward and consistent, making your code easier to read and understand
Function expression:
- Involves creating a function and assigning it to a variable. It can be anonymous or named
- Example
-
// Anonymous function expression; for named, there would be a space and a function name after the function keyword const greet = function(name) { return `Hello, ${name}!`; };
-
- Hoisting: func. expressions are not hoisted like func. declarations. The variable that holds the function is hoisted, but its value (the function itself) is not. This means you cannot call the function before it is defined
- When to use functional expression:
- Callbacks: function expressions are often used as arguments in higher-order functions like
setTimeout
,map
,filter
, etc. - Closures: when you need a function that retains access to its surrounding (lexical) scope
- Conditional definitions: if you need to define a function based on certain conditions
- IIFE: Function expressions are commonly used in Immediately Invoked Function Expressions (IIFE), which execute immediately after they are defined:
-
(function() { console.log('This function runs immediately!'); })();
-
- Callbacks: function expressions are often used as arguments in higher-order functions like
Arrow function
- Gets access to
...args
object, which is a syntax that allows you to represent an indefinite number of arguments as an array, similar to*args
unpacking in python
Arrays & array methods
- Looping through array: link (forEach, for(i in arr), for(x of arr), etc.)
.filter()
/.map()
/.reduce()
-
const numbers = [1, 2, 3, 4]; const evenNumbers = numbers.filter(num => num % 2 === 0); // [2,4] const doubled = numbers.map(num => num * 2); // [2, 4, 6, 8] const sum = numbers.reduce((acc, num) => acc + num, 0); // 10 '''
- Can also use
reduce()
to find an object in the array with a certain value criteria- Ex. find the oldest person object:
people.reduce((max, person) => person.age > max.age ? person : max)
- Ex. find the oldest person object:
-
.forEach()
: link.some()
/.every()
/.find()
: linksome()
/every()
is equivalent toany()
/all()
in Pythonsome()
:const containsPositive = numbers.some(num => num > 0)
// true for numbers = [-1,2,3], false for [-1,-2]every()
:const containsAllPositive = numbers.every(num => num > 0)
// true for numbers = [1,2,3], false for [-1,2,3]
find()
is the same syntax assome()
/every()
, except instead of a boolean it returns the object- Ex:
firstPositiveNumber = numbers.find(num => num > 0)
// 1 for [1,2,3]
- Ex:
Misc.
Data Manipulation: Destructuring, Spread, and Rest
- Destructuring: allows you to unpack values from arrays or properties from objects into distinct variables
-
const person = { name: 'John', age: 30 }; const { name, age } = person; // name = 'John'; age = 30
-
- Spread Operator (
...
): equivalent to Python unpacking- Purpose: expands (spreads) the elements of an array, object, or iterable into individual elements
- Used in: array/object creation, function arguments, or combining structures
- Also useful for creating a shallow copy of an array:
[...arr]
- Also useful for creating a shallow copy of an array:
-
const arr = [1, 2, 3]; const [first, ...last] = arr; // first = 1; last = [2, 3] const newArr = [...arr, 4, 5] // spreads elements of 'arr' into a new array; outputs [1,2,3,4,5] sum(...nums) // can also be passed as function arguments
- Rest Parameters (
...
): equivalent to Python packing- Purpose: gathers (collects) multiple arguments into a single array
- Used in: function parameter lists to handle an indefinite number of arguments
-
function sumAll(...numbers) { return numbers.reduce((acc, num) => acc + num, 0); } console.log(sumAll(1, 2, 3, 4)); // Outputs: 10
- Key differences:
- Spread: expands elements or values out of an iterable (e.g., array → individual items)
- Rest: collects multiple elements or values into a single array (e.g., multiple arguments → array)
- They are similar to how
*args
is handled in Python for (un)packing depending on if it's in the function definition or call
import
and export
JavaScript Modules: - Modules allow you to split your code into reusable pieces
-
// utils.js export function add(a, b) { return a + b; } // main.js import { add } from './utils'; console.log(add(2, 3)); // 5
-
Default and Named Exports
- Named Exports: You can export multiple values from a module
-
export const name = 'Alice'; export function greet() { console.log('Hello!'); }
-
- Default Exports: Each module can have one default export, which can be imported without curly braces
-
export default function() { console.log('Default Export'); }
-
localStorage
- Can use localStorage to persist data in the browser. Useful instead of cookies because they last longer
?.
)
Optional chaining (- Allows you to safely access deeply nested properties of an object without having to check each level for null or undefined
- Works on multiple types:
obj?.property
;obj?.[expression]
;obj?.method()
- Example:
-
let user = {}; console.log(user.profile.name); // throws an error: Cannot read property 'name' of undefined console.log(user.profile?.name); // returns undefined, no error
-
Specific scenarios
- Get difference between two arrays: link
- Slice an array:
arr.slice(start_index, end_index)
; ex: arr.slice(0,3); The last index is non-inclusive - Find certain values of an array: link
- Sleep function:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } sleep(1000).then(() => console.log('sleep'))
- Adding clear button for input field: link; link2
- Example in this repo: (link)[https://github.com/robbiehume/CS-Notes/blob/main/javascript/clearable_input.vue)
- Keep footer where it belongs: link
- Get certain key value from list of JSON objects:
cats.map((c) => c.name)
// get a list of all the names of cats - Access key as variable:
obj[var_name]
- Get browser to navigate to a URL: link
- Set element to same with as another element: link
- Check if a variable is equal to one of 2 or more possible values:
['val1', 'val2', 'val3'].inlcudes(var_name)