Fundamentals
6 min readRapid overview
- JavaScript Fundamentals
- Table of Contents
- Variables and Scope
- Variable Declarations
- Scope Types
- Hoisting
- Data Types
- Primitives
- Objects
- Type Checking
- Functions
- Function Declarations
- Arrow Functions vs Regular Functions
- Default Parameters
- Rest Parameters
- Closures
- Practical Use: Module Pattern
- Prototypes and Inheritance
- Prototype Chain
- ES6 Classes
- Asynchronous JavaScript
- Callbacks
- Promises
- Async/Await
- Event Loop
- Modules
- ES6 Modules
- CommonJS (Node.js)
- Best Practices
- Common Patterns
- Destructuring
- Spread Operator
- Optional Chaining
- Nullish Coalescing
JavaScript Fundamentals
Core JavaScript concepts essential for frontend development.
Table of Contents
- Variables and Scope
- Data Types
- Functions
- Closures
- Prototypes and Inheritance
- Asynchronous JavaScript
- Modules
Variables and Scope
Variable Declarations
// var - function-scoped, hoisted
var x = 10;
// let - block-scoped
let y = 20;
// const - block-scoped, cannot be reassigned
const z = 30;
Scope Types
Global Scope:
var globalVar = 'accessible everywhere';
function test() {
console.log(globalVar); // accessible
}
Function Scope:
function example() {
var functionScoped = 'only in function';
console.log(functionScoped); // works
}
console.log(functionScoped); // ReferenceError
Block Scope:
{
let blockScoped = 'only in block';
const alsoBlockScoped = 'also only in block';
}
console.log(blockScoped); // ReferenceError
Hoisting
// var hoisting
console.log(x); // undefined (declaration hoisted)
var x = 5;
// let/const hoisting (Temporal Dead Zone)
console.log(y); // ReferenceError
let y = 10;
// function hoisting
greet(); // works!
function greet() {
console.log('Hello!');
}
Data Types
Primitives
// String
const str = 'Hello';
const template = `World ${str}`;
// Number
const num = 42;
const float = 3.14;
const nan = NaN;
const inf = Infinity;
// Boolean
const bool = true;
// Undefined
let undef;
console.log(undef); // undefined
// Null
const nothing = null;
// Symbol (ES6)
const sym = Symbol('unique');
// BigInt (ES2020)
const bigInt = 9007199254740991n;
Objects
// Object literal
const person = {
name: 'John',
age: 30,
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
// Array
const arr = [1, 2, 3];
// Function
const func = function() {};
// Date
const date = new Date();
// RegExp
const regex = /pattern/;
Type Checking
typeof 'hello'; // 'string'
typeof 42; // 'number'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof {}; // 'object'
typeof []; // 'object' (arrays are objects!)
typeof null; // 'object' (historical bug)
typeof function() {}; // 'function'
// Better array check
Array.isArray([]); // true
// Better null check
value === null;
Functions
Function Declarations
// Function declaration
function add(a, b) {
return a + b;
}
// Function expression
const subtract = function(a, b) {
return a - b;
};
// Arrow function
const multiply = (a, b) => a * b;
// Arrow function with block
const divide = (a, b) => {
if (b === 0) throw new Error('Division by zero');
return a / b;
};
Arrow Functions vs Regular Functions
// Regular function - has its own 'this'
const obj1 = {
value: 10,
getValue: function() {
return this.value;
}
};
// Arrow function - inherits 'this' from parent scope
const obj2 = {
value: 10,
getValue: () => this.value // 'this' is from parent scope, not obj2
};
// Arrow functions cannot be constructors
const Person = (name) => {
this.name = name;
};
// new Person('John'); // TypeError
Default Parameters
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
greet(); // Hello, Guest!
greet('Alice'); // Hello, Alice!
Rest Parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
sum(1, 2, 3, 4); // 10
Closures
A closure is a function that remembers variables from its outer scope.
function createCounter() {
let count = 0; // private variable
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
Practical Use: Module Pattern
const calculator = (function() {
// Private variables
let result = 0;
// Public API
return {
add(x) {
result += x;
return this;
},
subtract(x) {
result -= x;
return this;
},
getResult() {
return result;
},
reset() {
result = 0;
return this;
}
};
})();
calculator.add(10).subtract(3).getResult(); // 7
Prototypes and Inheritance
Prototype Chain
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
const john = new Person('John');
john.greet(); // Hello, I'm John
// Prototype chain
console.log(john.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
ES6 Classes
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
console.log(`${this.name} barks`);
}
getBreed() {
return this.breed;
}
}
const dog = new Dog('Rex', 'Labrador');
dog.speak(); // Rex barks
Asynchronous JavaScript
Callbacks
function fetchData(callback) {
setTimeout(() => {
callback({ data: 'Some data' });
}, 1000);
}
fetchData((result) => {
console.log(result.data);
});
Promises
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve({ data: 'Some data' });
} else {
reject(new Error('Failed to fetch'));
}
}, 1000);
});
}
fetchData()
.then(result => console.log(result.data))
.catch(error => console.error(error));
Async/Await
async function getData() {
try {
const result = await fetchData();
console.log(result.data);
return result;
} catch (error) {
console.error('Error:', error);
}
}
getData();
Event Loop
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Output: 1, 4, 3, 2
// Microtasks (Promises) execute before macrotasks (setTimeout)
Modules
ES6 Modules
Exporting:
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export default class Calculator {
multiply(a, b) {
return a * b;
}
}
Importing:
// main.js
import Calculator, { PI, add } from './math.js';
console.log(PI); // 3.14159
console.log(add(2, 3)); // 5
const calc = new Calculator();
console.log(calc.multiply(4, 5)); // 20
CommonJS (Node.js)
Exporting:
// math.js
module.exports = {
PI: 3.14159,
add(a, b) {
return a + b;
}
};
Importing:
// main.js
const math = require('./math');
console.log(math.PI);
console.log(math.add(2, 3));
Best Practices
- Use const by default, let when you need to reassign, avoid var
- Prefer arrow functions for callbacks and short functions
- Use async/await over raw promises when possible
- Avoid callback hell - use promises or async/await
- Use strict mode (
'use strict';) - Check for null/undefined before accessing properties
- Use destructuring for cleaner code
- Avoid modifying prototypes of built-in objects
Common Patterns
Destructuring
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// Object destructuring
const { name, age, city = 'Unknown' } = person;
// Function parameter destructuring
function greet({ name, age }) {
console.log(`${name} is ${age} years old`);
}
Spread Operator
// Array spread
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// Object spread
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
Optional Chaining
const user = {
profile: {
name: 'John'
}
};
console.log(user?.profile?.name); // 'John'
console.log(user?.address?.city); // undefined (no error)
Nullish Coalescing
const value = null ?? 'default'; // 'default'
const num = 0 ?? 'default'; // 0 (only null/undefined trigger default)