Skip to main content

Command Palette

Search for a command to run...

⏳ JavaScript + TypeScript Fundamentals

Published
β€’4 min read
⏳ JavaScript + TypeScript Fundamentals
O

I'm a community-minded engineer based in Berlin, originally from Romania, and I grew up in sunny Spain. I combine the best of both communication and technical skills, with experience in both the engineering world and the business side of things. I'm proficient in a wide range of technologies like JavaScript, React.js, Redux, TypeScript, Node.js, HTML/CSS, Styled Components, SASS, and REST APIs. I love going beyond just writing code by sharing knowledge with my team through Communities of Practice (COPs), Employee Resource Groups (ERGs), and detailed technical documentation. My main interests are in frontend frameworks, web standards, accessibility (A11y), and Clean Code. My passion for programming started in high school when I built my first website. Since 2019, I've been working as a professional software developer, thriving in agile and iterative environments. Nearly five years later, I'm still excited to dive into code and collaborate with my colleagues. I'm very open and friendly, good at turning technical concepts into easy-to-understand information for everyone.

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

⏳ JavaScript + TypeScript Fundamentals