JavaScript 6 min read

JavaScript Primer: Essential Concepts

Master core JavaScript concepts including higher-order functions, arrow functions, closures, and the spread operator with practical examples.

MR

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 this binding)
  • Constructors
  • Functions that need arguments object

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

ConceptPurposeExample
Higher-order functionsFunctions as valuesarray.map(fn)
Arrow functionsShorter syntaxx => x * 2
ClosuresPrivate stateCounter pattern
Template literalsString interpolation`Hello ${name}`
Spread operatorExpand arrays/objects[...arr]
Rest parametersCollect 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

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

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

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.