Skip to main content

Command Palette

Search for a command to run...

⏳ JavaScript + TypeScript Fundamentals

Published
4 min readView as Markdown
⏳ JavaScript + TypeScript Fundamentals
O
I'm a Product Engineer at IDnow based in Berlin, originally from Romania and raised in sunny Spain. I build accessible, user-focused web applications with React, TypeScript, and modern frontend technologies. Beyond coding, I enjoy sharing knowledge through technical documentation, Communities of Practice (CoPs), and mentoring. I'm passionate about frontend architecture, web standards, accessibility (A11y), and writing clean, maintainable code.

Understanding the core building blocks of JavaScript and TypeScript helps you write better code, debug faster, and build more maintainable apps. This guide covers the must-know fundamentals including variable scopes, hoisting, closures, types, classes, and more.

🔁 var vs let vs const

JavaScript gives us three ways to declare variables:

  • var: the oldest, function-scoped, hoisted

  • let: block-scoped, reassignable

  • const: block-scoped, but cannot be reassigned

var car = "car";       // function scoped
let a = 5;              // block scoped
const b = 1;            // cannot reassign

🌀 Scope, Hoisting, Closures

Scope is where variables live and how accessible they are.

Hoisting is how var and function declarations are "lifted" to the top of their scope before code runs.

Closures allow inner functions to "remember" and access variables from their outer function, even after that outer function has finished executing.

🧙‍♀️ Hoisting in JavaScript

Definition: Hoisting is when JavaScript "remembers" all your variable and function declarations before running your code.

Memory allocation phase:

  • All var, function, and class declarations are stored in memory automatically before execution.

Key insights:

  • Only declarations are hoisted, not initializations.

  • let and const are hoisted but are not accessible before declaration.

  • Function declarations are hoisted fully. Function expressions are not.

🧳 Closures

A closure is when an inner function remembers variables from its outer function - even after the outer function is done.

Closures are not unique to JavaScript, but in JS, they are extremely useful and common. When you declare a function, it captures the scope in which it was defined - and remembers it.

const name = "Olga";

export function sayHello() {
  console.log(name);
}

Even if someone imports and runs sayHello, and doesn’t provide an argument, it will still find and use the name variable. That’s closure in action.

Here’s a more dynamic example using a function returning another function:

export function createSayHello() {
  const name = "Olga";

  return function sayHello() {
    console.log(name);
  }
}

const sayHelloOlga = createSayHello();
sayHelloOlga(); // logs "Olga"

You get not just the function - but the entire scope it was created in. That's the lexical environment 🌍

⚠️ Drawback of Closures

Closures put pressure on memory 🧠. All variables within the scope are still referenced as long as the function is used. This means:

  • They cannot be garbage collected

  • JavaScript cannot clean up that memory

  • The more closures you create, the more memory is retained

This is part of why JavaScript is often criticized for being less memory-efficient — it needs more RAM 💾.

📐 Types, Interfaces, Generics (TypeScript)

🧩 Types

let age: number = 25;
let name: string = "Olga";
let isAdmin: boolean = true;

🧷 Interfaces

interface User {
  id: number;
  name: string;
}

const user: User = { id: 1, name: "Olga" };

🎁 Generics

function wrapInArray<T>(value: T): T[] {
  return [value];
}

const nums = wrapInArray<number>(5); // [5]

📦 Objects, Arrays, Maps, Sets

🧱 Objects — Key-value pairs

const user = { name: "Alex", age: 22 };

📋 Arrays — Ordered collections

const numbers = [1, 2, 3];

🗺️ Maps — Key-value store with any type as key

const map = new Map();
map.set("a", 1);

🔢 Sets — Only unique values allowed

const set = new Set([1, 2, 2, 3]); // {1, 2, 3}

🏛️ Classes, Inheritance, this

class Animal {
  constructor(public name: string) {}

  speak() {
    console.log(`${this.name} makes a sound`);
  }
}

class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks`);
  }
}

const d = new Dog("Rex");
d.speak(); // Rex barks

🔁 this Keyword

  • Refers to the current context (object, function, or global)

  • Arrow functions do not have their own this — they inherit from the parent scope

Common Gotchas & Tips

✅ Prefer const by default. Use let only when needed.
❌ Don’t use == — use === for strict equality
✅ Use optional chaining ?. to safely access nested properties
✅ Use destructuring for cleaner code
❌ Avoid mutating arrays/objects directly — prefer immutability