[2026] JavaScript Variables and Data Types | let, const, and var Explained

[2026] JavaScript Variables and Data Types | let, const, and var Explained

이 글의 핵심

Deep dive into JavaScript variables: let, const, var, scope, hoisting, primitives, type coercion, and common mistakes—with runnable examples.

Introduction

What is a variable?

A variable is a named place to store data. JavaScript is a dynamically typed language: a variable’s “type” is determined by the value it holds.

1. Declarations: let, const, var

let: reassignment allowed

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let age = 25;
console.log(age);  // 25
age = 26;  // reassignment OK
console.log(age);  // 26
// Declare now, assign later
let name;
console.log(name);  // undefined
name = "Alice";
console.log(name);  // Alice

const: no reassignment

const declares a constant binding; you cannot reassign it: 다음은 javascript를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const PI = 3.14159;
console.log(PI);  // 3.14159
// Reassignment throws
// PI = 3.14;  // TypeError: Assignment to constant variable
// Must initialize at declaration
// const x;  // SyntaxError: Missing initializer in const declaration
// Important: object/array *contents* can still change
const person = { name: "Alice", age: 25 };
// The binding `person` cannot be reassigned
// But properties can change
person.age = 26;  // ✅ OK (mutate object contents)
console.log(person);  // { name: 'Alice', age: 26 }
// person = {};  // ❌ TypeError (rebinding not allowed)
const arr = [1, 2, 3];
// The binding `arr` cannot be reassigned
// Elements can change
arr.push(4);  // ✅ OK
console.log(arr);  // [1, 2, 3, 4]
arr[0] = 10;  // ✅ OK
console.log(arr);  // [10, 2, 3, 4]
// arr = [];  // ❌ TypeError

What const really means: 아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// const fixes the *reference* the variable holds
// The referenced object’s contents can still change
const obj = { x: 1 };
// obj points at a specific object in memory
obj.x = 2;  // ✅ mutate contents (same reference)
// obj = { x: 2 };  // ❌ new object (new reference)

Deep immutability: 아래 코드는 javascript를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Object.freeze(): shallow freeze
const person = Object.freeze({ name: "Alice", age: 25 });
// person.age = 26;  // ignored (strict mode throws)
console.log(person.age);  // 25
// Nested objects are not frozen automatically
const user = Object.freeze({
    name: "Alice",
    address: { city: "Seoul" }  // inner object not frozen
});
user.address.city = "Busan";  // ✅ still mutates nested object
console.log(user.address.city);  // Busan

아래 코드는 javascript를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

var x = 10;
var x = 20;  // redeclaration allowed (problematic!)
console.log(x);  // 20
// Function scope (ignores block scope)
if (true) {
    var y = 30;
}
console.log(y);  // 30 (accessible outside the block!)
// Hoisting surprise
console.log(z);  // undefined (not an error!)
var z = 40;

let vs const vs var

letconstvar
Reassignment
Redeclare (same scope)
ScopeBlockBlockFunction
HoistingTDZTDZundefined
Recommended
TDZ (Temporal Dead Zone): accessing before declaration throws ReferenceError.
아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// let/const: TDZ
// console.log(x);  // ReferenceError
let x = 10;
// var: hoisted as undefined
console.log(y);  // undefined
var y = 20;

2. Scope

Block scope

let and const are block-scoped: 다음은 javascript를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

{
    let x = 10;
    const y = 20;
    console.log(x, y);  // 10 20
}
// console.log(x);  // ReferenceError
// console.log(y);  // ReferenceError
if (true) {
    let z = 30;
    console.log(z);  // 30
}
// console.log(z);  // ReferenceError
for (let i = 0; i < 3; i++) {
    console.log(i);  // 0 1 2
}
// console.log(i);  // ReferenceError
// Nested blocks
{
    let x = 10;
    {
        let x = 20;  // shadowing
        console.log(x);  // 20
    }
    console.log(x);  // 10
}
// Closures in loops: let creates a new binding per iteration
for (let i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i);  // 0 1 2
    }, 100);
}
// With var, one shared binding
for (var j = 0; j < 3; j++) {
    setTimeout(() => {
        console.log(j);  // 3 3 3
    }, 100);
}

Benefits of block scope:

  1. Fewer accidental collisions
  2. Variables can be collected when the block ends
  3. Clearer lifetime
  4. Safer with closures in loops

Function scope

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

function test() {
    let x = 10;
    var y = 20;
    if (true) {
        let x = 30;  // new block-scoped x
        var y = 40;  // same function-scoped y
        console.log(x, y);  // 30 40
    }
    console.log(x, y);  // 10 40
}
test();

Global scope

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let globalVar = "global";
function test() {
    console.log(globalVar);
}
test();
// Browser: window
// var global = "test";
// console.log(window.global);
// Node.js: global
// global.myVar = "test";

3. Data types

Primitive types

JavaScript has seven primitive types.

1. Number

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let integer = 42;
let float = 3.14;
let negative = -10;
let inf = Infinity;
let negInf = -Infinity;
let notANumber = NaN;
console.log(10 / 0);  // Infinity
console.log("abc" / 2);  // NaN
console.log(isNaN(NaN));  // true
console.log(isNaN(10));   // false
console.log(Number.MAX_SAFE_INTEGER);
console.log(Number.MIN_SAFE_INTEGER);

2. String

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let str1 = "double quotes";
let str2 = 'single quotes';
let str3 = `template literal`;
let name = "Alice";
let age = 25;
let message = `Hello, ${name}! You are ${age}.`;
console.log(message);
let multiline = `line one
line two
line three`;
let escaped = "He said \"Hello\"";
console.log(escaped);

3. Boolean

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let isTrue = true;
let isFalse = false;
console.log(10 > 5);   // true
console.log(10 === 5); // false

4. undefined

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let x;
console.log(x);  // undefined
console.log(typeof x);  // undefined
function test() {
    // no return
}
console.log(test());  // undefined

5. null

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let empty = null;
console.log(empty);  // null
console.log(typeof empty);  // "object" (historical quirk)
let x;           // undefined (declared only)
let y = null;    // explicit empty

6. Symbol (ES6+)

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let sym1 = Symbol("description");
let sym2 = Symbol("description");
console.log(sym1 === sym2);  // false (always unique)
let obj = {
    [sym1]: "value1"
};
console.log(obj[sym1]);  // value1

7. BigInt (ES2020+)

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let bigNum = 9007199254740991n;
let bigNum2 = BigInt("9007199254740991");
console.log(bigNum + 1n);
// Cannot mix with Number without conversion
// console.log(bigNum + 1);  // TypeError
console.log(bigNum + BigInt(1));  // OK

Reference types

Object

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let person = {
    name: "Alice",
    age: 25,
    greet: function() {
        console.log(`Hello, I'm ${this.name}.`);
    }
};
console.log(person.name);
person.greet();

Array

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, null, { name: "Alice" }];
console.log(numbers[0]);
console.log(numbers.length);

Function

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

function add(a, b) {
    return a + b;
}
console.log(typeof add);  // function

4. Type checks and conversion

typeof

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

console.log(typeof 42);         // number
console.log(typeof "hello");    // string
console.log(typeof true);       // boolean
console.log(typeof undefined);  // undefined
console.log(typeof null);       // object (quirk)
console.log(typeof {});         // object
console.log(typeof []);         // object
console.log(typeof function(){}); // function
console.log(Array.isArray([]));  // true
console.log(Array.isArray({}));  // false

Coercion

To string

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let num = 42;
let str = String(num);
console.log(str, typeof str);
let str2 = num.toString();
let result = 42 + " apples";
console.log(result);

To number

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let str = "42";
let num = Number(str);
console.log(parseInt("42px"));
console.log(parseFloat("3.14abc"));
console.log(parseInt("abc"));  // NaN
console.log("42" - 10);
console.log("42" * 2);
console.log(+"42");

To boolean

다음은 javascript를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

console.log(Boolean(1));
console.log(Boolean(0));
console.log(Boolean("hello"));
console.log(Boolean(""));
// Falsy values
console.log(Boolean(false));
console.log(Boolean(0));
console.log(Boolean(""));
console.log(Boolean(null));
console.log(Boolean(undefined));
console.log(Boolean(NaN));
// Truthy
console.log(Boolean(1));
console.log(Boolean("hello"));
console.log(Boolean([]));
console.log(Boolean({}));
if ("hello") {
    console.log("Truthy!");
}

5. Hoisting

What is hoisting?

Hoisting means declarations are conceptually moved to the top of their scope (behavior differs for var, let/const, and functions).

var hoisting

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

console.log(x);  // undefined
var x = 10;
console.log(x);  // 10
// Conceptually similar to:
var x;
console.log(x);
x = 10;
console.log(x);

let/const and the TDZ

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// console.log(x);  // ReferenceError (TDZ)
let x = 10;
// console.log(y);  // ReferenceError
const y = 20;

Function hoisting

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

greet();  // works (function declaration hoisted)
function greet() {
    console.log("Hello!");
}
// sayHello();  // ReferenceError (function expression not hoisted)
const sayHello = function() {
    console.log("Hello!");
};
sayHello();

6. Practical examples

Example 1: swapping variables

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

let a = 10;
let b = 20;
let temp = a;
a = b;
b = temp;
console.log(a, b);  // 20 10
let x = 10;
let y = 20;
[x, y] = [y, x];
console.log(x, y);  // 20 10

Example 2: a small getType helper

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

function getType(value) {
    if (value === null) return "null";
    if (Array.isArray(value)) return "array";
    return typeof value;
}

Example 3: safe integer parsing

다음은 간단한 javascript 코드 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

function safeParseInt(value, defaultValue = 0) {
    const parsed = parseInt(value);
    return isNaN(parsed) ? defaultValue : parsed;
}

Example 4: config and immutability

다음은 javascript를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const config = {
    apiUrl: "https://api.example.com",
    timeout: 5000
};
config.timeout = 10000;  // OK (mutate object)
const frozenConfig = Object.freeze({
    apiUrl: "https://api.example.com",
    timeout: 5000
});
const user = Object.freeze({
    name: "Alice",
    address: { city: "Seoul" }
});
user.address.city = "Busan";  // nested still mutable
function deepFreeze(obj) {
    Object.freeze(obj);
    Object.keys(obj).forEach(key => {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            deepFreeze(obj[key]);
        }
    });
    return obj;
}

7. Common mistakes

Mistake 1: using var in loops

아래 코드는 javascript를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}

Mistake 2: misunderstanding const

const arr = [1, 2, 3];
arr.push(4);
arr[0] = 100;

Mistake 3: == vs ===

console.log(5 == "5");
console.log(5 === "5");

Mistake 4: accidental string concatenation

console.log("10" + 20);
console.log(Number("10") + 20);

Mistake 5: leaking globals

아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// count = 0;  // creates global in sloppy mode — avoid
let count = 0;
function increment() {
    count++;
}

8. Practical tips

Tip 1: const by default

const API_URL = "https://api.example.com";
let retryCount = 0;

Tip 2: meaningful names

let userAge = 25;
let scores = [1, 2, 3];
const MAX_USERS = 100;

Tip 3: strict mode

"use strict";
// x = 10;  // ReferenceError

9. Exercises

Exercise 1: rotate three variables

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

let a = 1;
let b = 2;
let c = 3;
[a, b, c] = [c, a, b];
console.log(a, b, c);  // 3 1 2

Exercise 2: toNumber

다음은 간단한 javascript 코드 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

function toNumber(value, defaultValue = 0) {
    const num = Number(value);
    return isNaN(num) ? defaultValue : num;
}

Exercise 3: remove falsy values

function removeFalsy(arr) {
    return arr.filter(Boolean);
}

Summary

Key points

  1. Declarations: const default, let when rebinding, avoid var in new code.
  2. Scope: block scope for let/const, function scope for var.
  3. Types: seven primitives plus objects, arrays, functions.
  4. Coercion: prefer explicit Number/String/Boolean when unclear.
  5. Hoisting: var initializes as undefined; let/const use TDZ.

Best practices

  1. Use const, then let.
  2. Prefer === over ==.
  3. Use "use strict".
  4. Prefer descriptive names.
  5. Minimize globals.

Next steps


... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3