Functions are reusable blocks of code. Objects store collections of key-value pairs. Together they form the backbone of JavaScript programs.
A function declaration defines a named function that is hoisted to the top of its scope:
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("Alice")); // "Hello, Alice!"
A function expression assigns a function to a variable. It is not hoisted:
const greet = function(name) {
return "Hello, " + name + "!";
};
console.log(greet("Bob")); // "Hello, Bob!"
Arrow functions provide a concise syntax and do not have their own this binding:
const greet = (name) => {
return `Hello, ${name}!`;
};
// Even shorter with implicit return
const greetShort = (name) => `Hello, ${name}!`;
console.log(greet("Charlie")); // "Hello, Charlie!"
Functions can have default parameters and rest parameters:
function multiply(a, b = 1) {
return a * b;
}
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(multiply(5)); // 5 (b defaults to 1)
console.log(sum(1, 2, 3, 4)); // 10
this. Use function declarations for top-level functions that need hoisting.
Objects store data as key-value pairs using curly braces:
const person = {
firstName: "Alice",
lastName: "Johnson",
age: 30,
greet() {
console.log(`Hi, I'm ${this.firstName}`);
}
};
// Accessing properties
console.log(person.firstName); // "Alice"
console.log(person["lastName"]); // "Johnson"
person.greet(); // "Hi, I'm Alice"
Use dot notation for known property names. Use bracket notation for dynamic keys or names with special characters:
const key = "age";
console.log(person[key]); // 30
const product = { "product-name": "Widget" };
console.log(product["product-name"]); // "Widget"
this Keywordthis refers to the object that owns the executing code:
const car = {
brand: "Toyota",
describe() {
console.log(`This is a ${this.brand}`);
}
};
car.describe(); // "This is a Toyota"
Constructor functions create objects with shared structure (pre-ES6 pattern):
function Person(name, age) {
this.name = name;
this.age = age;
}
const alice = new Person("Alice", 30);
console.log(alice.name); // "Alice"
Classes provide a cleaner syntax for constructor functions and inheritance:
class Animal {
constructor(name, sound) {
this.name = name;
this.sound = sound;
}
speak() {
console.log(`${this.name} says ${this.sound}`);
}
}
class Dog extends Animal {
constructor(name) {
super(name, "Woof");
}
}
const dog = new Dog("Rex");
dog.speak(); // "Rex says Woof"
JavaScript has three levels of scope:
// Global scope
let globalVar = "I'm global";
function test() {
// Function scope
let funcVar = "I'm local to this function";
if (true) {
// Block scope
let blockVar = "I'm local to this block";
console.log(globalVar); // Accessible
console.log(funcVar); // Accessible
}
// console.log(blockVar); // ReferenceError
}
A closure is a function that remembers its outer variables even after the outer function has returned:
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
createCounter() creates an independent closure with its own count.
createGreeter function that takes a greeting word and returns a new function. The returned function should accept a name and log the greeting followed by the name. Then use it to create a "Hello" greeter and a "Goodbye" greeter. Also write a Rectangle class with width, height, and an area() method.