JavaScript Primer: Essential Concepts
Master core JavaScript concepts including higher-order functions, arrow functions, closures, and the spread operator with practical examples.
Moshiour Rahman
Advertisement
Overview
JavaScript has evolved significantly with ES6 and beyond. This primer covers essential concepts that every JavaScript developer should know: higher-order functions, arrow functions, closures, and modern operators.
Functions as First-Class Citizens
In JavaScript, functions are objects. This means you can:
- Assign them to variables
- Pass them as arguments
- Return them from other functions
Passing Functions as Arguments
function greet(nameFunction) {
return "Hello " + nameFunction() + "!";
}
const result = greet(function() {
return "TechyOwls";
});
console.log(result);
// Output: Hello TechyOwls!
Chaining Functions
Functions can call other functions, enabling powerful composition:
function createMessage(nameFunction) {
return "Hello " + nameFunction() + "!";
}
function displayMessage(nameFunction, printFunction) {
printFunction(createMessage(nameFunction));
}
displayMessage(
function() { return "TechyOwls"; },
console.log
);
// Output: Hello TechyOwls!
Arrow Functions
Arrow functions (also called “fat arrow” or “lambda expressions”) provide a shorter syntax for writing functions.
Basic Syntax
// Traditional function
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
// With single parameter (parentheses optional)
const double = x => x * 2;
// With no parameters
const sayHello = () => "Hello!";
Converting Our Example
// Before
function createMessage(nameFunction) {
return "Hello " + nameFunction() + "!";
}
function displayMessage(nameFunction, printFunction) {
printFunction(createMessage(nameFunction));
}
// After
const createMessage = nameFunction => "Hello " + nameFunction() + "!";
const displayMessage = (nameFunction, printFunction) =>
printFunction(createMessage(nameFunction));
displayMessage(() => "TechyOwls", console.log);
// Output: Hello TechyOwls!
When to Use Arrow Functions
Use arrow functions for:
- Callbacks and inline functions
- Array methods (map, filter, reduce)
- Short, simple functions
Don’t use for:
- Object methods (no
thisbinding) - Constructors
- Functions that need
argumentsobject
Closures
A closure is when an inner function has access to variables from its outer function, even after the outer function has returned.
Basic Closure Example
function createGreeting(name) {
const weather = "sunny"; // Local variable
function innerGreeting() {
return `Hello ${name}! Today is ${weather}.`;
}
return innerGreeting();
}
console.log(createGreeting("TechyOwls"));
// Output: Hello TechyOwls! Today is sunny.
Practical Closure: Counter
function createCounter() {
let count = 0; // Private variable
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
console.log(counter.decrement()); // 1
The count variable is “closed over” - it persists between function calls but isn’t accessible from outside.
Closure Pitfall: Loop Variables
// Problem: All buttons log 5
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 5 5 5 5 5
// Solution 1: Use let
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 0 1 2 3 4
// Solution 2: Create closure
for (var i = 0; i < 5; i++) {
((j) => {
setTimeout(() => console.log(j), 100);
})(i);
}
// Output: 0 1 2 3 4
Working with Strings
JavaScript provides useful string methods:
Common String Methods
const message = "Hello TechyOwls!";
// charAt - get character at index
message.charAt(0); // "H"
message.charAt(6); // "T"
// concat - join strings
"Hello ".concat("World"); // "Hello World"
// indexOf - find position
message.indexOf("T"); // 6
message.indexOf("x"); // -1 (not found)
// includes - check if contains
message.includes("Techy"); // true
// slice - extract portion
message.slice(0, 5); // "Hello"
message.slice(6); // "TechyOwls!"
// split - convert to array
message.split(" "); // ["Hello", "TechyOwls!"]
// toLowerCase/toUpperCase
message.toLowerCase(); // "hello techyowls!"
message.toUpperCase(); // "HELLO TECHYOWLS!"
Template Literals
Use backticks for string interpolation:
const name = "TechyOwls";
const age = 25;
// Old way
const message = "Hello " + name + ", you are " + age + " years old.";
// Template literal (much cleaner!)
const message = `Hello ${name}, you are ${age} years old.`;
// Multiline strings
const html = `
<div class="card">
<h2>${name}</h2>
<p>Age: ${age}</p>
</div>
`;
The Spread Operator
The spread operator (...) expands arrays or objects.
Spreading Arrays as Arguments
function printItems(num, str, bool) {
console.log(`Number: ${num}`);
console.log(`String: ${str}`);
console.log(`Boolean: ${bool}`);
}
const myArray = [100, "Adam", true];
// Old way
printItems(myArray[0], myArray[1], myArray[2]);
// With spread operator
printItems(...myArray);
Concatenating Arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// Combine arrays
const combined = [...arr1, ...arr2];
// Output: [1, 2, 3, 4, 5, 6]
// Insert into array
const inserted = [0, ...arr1, 3.5, ...arr2, 7];
// Output: [0, 1, 2, 3, 3.5, 4, 5, 6, 7]
Copying Arrays
const original = [1, 2, 3];
// Shallow copy
const copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3] - unchanged
console.log(copy); // [1, 2, 3, 4]
Spreading Objects
const user = { name: "John", age: 30 };
// Copy and extend
const extendedUser = { ...user, email: "john@example.com" };
// { name: "John", age: 30, email: "john@example.com" }
// Override properties
const updatedUser = { ...user, age: 31 };
// { name: "John", age: 31 }
Rest Parameters
The ... syntax also collects remaining arguments:
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3, 4)); // 10
Summary
| Concept | Purpose | Example |
|---|---|---|
| Higher-order functions | Functions as values | array.map(fn) |
| Arrow functions | Shorter syntax | x => x * 2 |
| Closures | Private state | Counter pattern |
| Template literals | String interpolation | `Hello ${name}` |
| Spread operator | Expand arrays/objects | [...arr] |
| Rest parameters | Collect arguments | (...args) |
Conclusion
These JavaScript concepts are fundamental to modern development:
- Functions are first-class citizens
- Arrow functions provide cleaner syntax
- Closures enable private state
- Spread/rest operators simplify array manipulation
Key Takeaways:
- Use arrow functions for callbacks
- Leverage closures for encapsulation
- Prefer template literals over concatenation
- Use spread for immutable operations
Advertisement
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
JavaScript Array Methods: Map and Filter Explained
Master JavaScript's ES6 array helper methods map() and filter() with practical examples. Learn how to transform and filter arrays like a pro.
JavaScriptTurborepo: High-Performance Monorepo Build System
Master Turborepo for monorepo management. Learn workspace setup, caching, pipelines, and build performant multi-package JavaScript projects.
JavaScriptReact Hooks Complete Guide: useState to Custom Hooks
Master all React hooks from basics to advanced. Learn useState, useEffect, useContext, useReducer, useMemo, useCallback, and create custom hooks.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.