#JavaScript#Fundamentals

JavaScript Basics and Language Fundamentals

Deep dive into JavaScript internals: primitive vs reference types, memory allocation, hoisting mechanics, type coercion rules, and scope chains explained with practical examples.

By Pratik Rai

A deep, practical guide to how JavaScript actually works

JavaScript looks simple on the surface. You can write a few lines, manipulate the DOM, fetch data, and ship features quickly. But under the hood, JavaScript has nuanced rules around memory, execution, coercion, and scope that directly affect correctness, performance, and debuggability. For the official specification, see the ECMAScript Language Specification.

This article goes step by step through the core language fundamentals that every serious JavaScript developer must understand. Not as isolated topics, but as a connected system.


1. JavaScript Data Types

Primitive vs Non-Primitive

JavaScript has seven primitive types and one non-primitive category.

Primitive Types

Primitive values are immutable and stored by value.

  1. number
  2. string
  3. boolean
  4. undefined
  5. null
  6. symbol
  7. bigint

Example:

JSfile.js
1let a = 10; 2let b = a; 3b = 20; 4 5console.log(a); // 10

Here, a and b hold independent copies of the value.

Non-Primitive Types

Non-primitives are objects, including:

  • Objects
  • Arrays
  • Functions
  • Dates
  • Maps, Sets, etc.

They are stored by reference.

JSfile.js
1let obj1 = { x: 10 }; 2let obj2 = obj1; 3 4obj2.x = 20; 5console.log(obj1.x); // 20

Both variables point to the same memory location.

Key takeaway: Primitive types copy values. Objects copy references.


2. var, let, and const

var

  • Function-scoped
  • Hoisted and initialized with undefined
  • Can be re-declared and re-assigned
JSfile.js
1console.log(a); // undefined 2var a = 10;

This behavior is a common source of bugs and is why var is largely avoided today.

let

  • Block-scoped
  • Hoisted but not initialized
  • Can be re-assigned but not re-declared in the same scope
JSfile.js
1let x = 10; 2x = 20; // allowed

const

  • Block-scoped
  • Must be initialized
  • Cannot be re-assigned
JSfile.js
1const y = 10; 2// y = 20; ❌ error

Important clarification: const does not make objects immutable.

JSfile.js
1const user = { name: "A" }; 2user.name = "B"; // allowed

It only prevents reassignment of the reference.


3. Hoisting in JavaScript

Hoisting is JavaScript’s behavior of moving declarations to the top of the scope during compilation.

What gets hoisted:

  • Variable declarations
  • Function declarations

What does not get hoisted:

  • Variable initializations
  • Function expressions

Example:

JSfile.js
1console.log(a); // undefined 2var a = 10;

This is effectively treated as:

JSfile.js
1var a; 2console.log(a); 3a = 10;

Function declarations are fully hoisted:

JSfile.js
1sayHello(); 2 3function sayHello() { 4 console.log("Hello"); 5}

Function expressions are not:

JSfile.js
1sayHi(); // error 2 3const sayHi = () => {};

4. Temporal Dead Zone (TDZ)

The Temporal Dead Zone is the time between entering a scope and initializing a let or const variable.

JSfile.js
1console.log(a); // ReferenceError 2let a = 10;

The variable exists in memory, but it cannot be accessed.

Why TDZ exists:

  • To prevent accessing variables before they are properly initialized
  • To avoid bugs that var introduced

TDZ enforces safer coding practices.


5. null vs undefined

undefined

  • Means a variable exists but has no value
  • Assigned automatically by JavaScript
JSfile.js
1let a; 2console.log(a); // undefined

null

  • Explicitly assigned
  • Represents intentional absence of value
JSfile.js
1let b = null;

Key difference:

  • undefined is a default state
  • null is an intentional decision

6. == vs ===

== (Loose Equality)

  • Performs type coercion
  • Compares values after conversion
JSfile.js
10 == "0"; // true 2false == 0; // true 3null == undefined; // true

=== (Strict Equality)

  • No type coercion
  • Compares both type and value
JSfile.js
10 === "0"; // false

Rule of thumb: Use === unless you have a very specific reason not to.

Loose equality introduces implicit conversions that are hard to reason about.


7. Type Coercion Rules

Type coercion is JavaScript automatically converting values from one type to another.

String coercion

JSfile.js
1"5" + 1; // "51"

Numeric coercion

JSfile.js
1"5" - 1; // 4

Boolean coercion

Falsy values:

  • false
  • 0
  • ""
  • null
  • undefined
  • NaN

Everything else is truthy.

JSfile.js
1if ("0") { 2 // this runs 3}

Understanding coercion is critical for writing predictable conditions.


8. typeof Quirks

The typeof operator is useful but imperfect.

JSfile.js
1typeof 10; // "number" 2typeof "a"; // "string" 3typeof true; // "boolean" 4typeof undefined; // "undefined" 5typeof function(){}; // "function"

The famous bug:

JSfile.js
1typeof null; // "object"

This is a historical bug in JavaScript that cannot be fixed without breaking the web.

Correct way to check null:

JSfile.js
1value === null;

9. NaN and Edge Cases

NaN stands for Not a Number.

JSfile.js
1Number("abc"); // NaN

Important properties:

JSfile.js
1NaN === NaN; // false

To check NaN:

JSfile.js
1Number.isNaN(value);

Avoid:

JSfile.js
1isNaN("abc"); // true (coerces first)

Always prefer Number.isNaN.


10. Pass by Value vs Pass by Reference

JavaScript technically uses pass by value, but the value for objects is a reference.

Primitive example

JSfile.js
1function change(x) { 2 x = 20; 3} 4 5let a = 10; 6change(a); 7console.log(a); // 10

Object example

JSfile.js
1function change(obj) { 2 obj.x = 20; 3} 4 5let o = { x: 10 }; 6change(o); 7console.log(o.x); // 20

The reference is copied, not the object itself.


11. Shallow Copy vs Deep Copy

Shallow Copy

Shallow copy copies only the first level.

JSfile.js
1const obj = { a: 1, b: { c: 2 } }; 2const copy = { ...obj }; 3 4copy.b.c = 5; 5console.log(obj.b.c); // 5

Methods that create shallow copies:

  • Spread operator
  • Object.assign
  • Array.slice

Deep Copy

Deep copy creates a completely independent copy.

Common approaches:

JSfile.js
1JSON.parse(JSON.stringify(obj));

Limitations:

  • Loses functions
  • Breaks dates
  • Cannot handle circular references

Better approach:

Goal: Build a rock-solid mental model of JavaScript core language fundamentals so the language stops surprising you.

Frequently asked questions

Which fundamentals come up most in frontend interviews?
Types and coercion, scope and closures, `this` binding, prototypes, and the event loop. Nearly every JavaScript question is one of those five wearing a costume, which is why they are worth understanding as mechanisms rather than as definitions to recite.
What is the honest answer about == versus ===?
Use `===` and convert explicitly. The coercion rules behind `==` are convoluted enough that most teams ban it, with the single common exception of `x == null` as a check for both `null` and `undefined`. Interviewers ask to see whether you know the rules exist, not to hear you defend using them.
Why does typeof null return "object"?
An implementation detail from the first version of JavaScript that became impossible to change without breaking the web. It is worth knowing as a fact, and it is worth knowing what to do about it — check `value === null` explicitly rather than relying on `typeof`.
What is the difference between undefined and null in practice?
`undefined` is what the language gives you when nothing was assigned — a missing property, a parameter not passed, a function with no return. `null` is a value you assign deliberately to mean "nothing here". The convention matters because it makes the absence intentional and readable, which is the answer interviewers are listening for.

Related Challenges

Continue learning with these related challenges

View All
JavaScript

Get smart in javascript

Level up your JavaScript expertise with advanced tips, tricks, and gotchas. Master closures, hoisting, coercion, and event loop behavior to write cleaner, bug-free code.

JavaScript · ES6Pratik Rai ·

JavaScript

JS Output Challenges

Test your JavaScript skills by predicting console output for tricky code snippets. Covers hoisting, closures, this binding, async operations, and event loop quiz questions.

JavaScript · ES6Pratik Rai ·

JavaScript

Debounce

Master the debounce technique in JavaScript to control function execution frequency. Essential for optimizing search inputs, resize handlers, and preventing excessive API calls.

JavaScript · Closures · AsyncPratik Rai ·