JavaScript 변수 선언 —
전역·지역·블록 스코프 완전 정리
변수 하나(x)는 어디서든 쓸 수 있는데, 다른 변수(y, b)는 특정 구간을 벗어나면 존재 자체가 사라진다. 그리고 실수로 let을 빼먹은 변수(z)는 원래 의도와 다르게 동작한다. 이 세 가지 현상을 한 코드 안에서 확인해본다.
변수 선언, 전역/지역/블록 변수
함수 f() 내 지역변수 y = 20
전역변수 x = 10
전역변수 z = 30
f()가 호출되는 그 순간, 함수 안의 if 블록이 먼저 실행되며 "b = 41"을 출력하고, 그다음 함수 안 나머지 코드가 "y = 20"을 출력한다. 함수가 끝난 뒤에야 바깥 코드가 "x = 10", "z = 30"을 출력한다. 코드는 위에서 아래로 실행되는 게 아니라 호출된 순서대로 실행된다.변수는 값을 담아두고 나중에 그 이름으로 다시 꺼내 쓰기 위한 저장 공간이다. 그런데 이 상자를 아무 데서나 만들 수 있는 게 아니라, 어느 위치에서 만들었는지에 따라 그 상자를 열어볼 수 있는 범위가 달라진다. 이 범위를 스코프(scope, 유효범위)라고 부른다.
왜 이런 규칙이 필요할까? 만약 모든 변수가 어디서든 접근 가능하다면, 큰 프로그램에서는 변수 이름이 서로 충돌하고, 함수 하나를 고치다가 전혀 상관없는 다른 코드가 망가지는 일이 생긴다. 스코프는 "이 변수는 여기까지만 책임진다"는 경계선을 그어서 코드를 안전하게 나누는 장치다.
let x;는 "x라는 이름의 변수 상자를 만들겠다"는 선언이다. 아직 값은 안 들어있고(undefined), 나중에 x = 10;처럼 대입해서 값을 채운다. 선언과 대입을 한 줄로 합쳐 let x = 10;처럼 쓸 수도 있다.
원본 코드의 주석에 "var로 선언해도 동일"이라고 적혀 있는데, 값을 저장하고 꺼내 쓰는 기본 동작은 let이나 var나 똑같다. 차이는 뒤에서 다룰 블록 스코프를 지키느냐 아니냐에 있다.
변수 x는 <script> 태그 최상단, 즉 어떤 함수 안에도 속하지 않은 위치에서 let x;로 선언됐다. 함수 밖(전역)에서 선언된 변수는 코드 전체에서 접근 가능한 전역변수가 된다.
그래서 함수 f() 안에서 x = 10;으로 값을 넣어도, 함수가 끝난 뒤 바깥의 document.write("전역변수 x = " + x + "<br>")에서 그 값 10을 그대로 읽을 수 있다. 같은 상자를 안에서도 밖에서도 공유하는 것이다.
변수 y는 function f() { ... }의 중괄호 안쪽에서 let y;로 선언됐다. 함수 안에서 선언된 변수는 그 함수가 실행되는 동안에만 존재하는 지역변수가 되고, 함수가 끝나면 사라진다.
그래서 마지막 줄에서 document.write("전역변수 z = " + z) 다음에 만약 y를 출력하려 하면 "y is not defined" 에러가 난다. y라는 상자 자체가 함수 f()의 실행이 끝나는 순간 치워지기 때문이다.
변수 b는 함수 f() 안이 아니라, 그보다 한 단계 더 안쪽인 if(y == 20) { ... }의 중괄호 안에서 let b = 40;으로 선언됐다. let은 함수 단위가 아니라 중괄호 {} 블록 단위로 스코프를 만들기 때문에, b는 이 if 블록을 벗어나는 순간 존재하지 않게 된다.
그래서 원본 코드 주석처럼 if 블록이 끝난 직후 줄에서도 b에는 접근할 수 없다. b++;로 41이 된 값은 블록 안에서 출력(document.write)하는 그 순간에만 쓸 수 있고, 블록을 나가면 상자째로 사라진다.
전역 · 함수 · 블록은 서로 독립된 것이 아니라, 바깥 상자 안에 안쪽 상자가 들어있는 구조다. 안쪽 상자에서는 바깥 상자의 내용물을 꺼내볼 수 있지만, 바깥에서는 안쪽 상자를 열 수 없다.
if 블록 안 조건식 if(y == 20)은 블록 바깥쪽인 함수 스코프에 있는 y를 참조한다. 자바스크립트는 변수를 찾을 때 가장 가까운 안쪽 스코프부터 시작해서, 없으면 한 단계씩 바깥으로 나가며 찾는다. 이 탐색 경로를 스코프 체인(scope chain)이라 부른다.
반대로 함수 스코프에서 b를 찾으려 하면, 함수 스코프에는 없고 더 바깥인 전역 스코프로도 찾아 나가지만 거기에도 없으므로 "정의되지 않음" 에러가 난다. 스코프 체인은 안에서 밖으로만 뻗어나가지, 밖에서 안으로 내려가는 경로는 애초에 없다.
함수 f() 안의 z = 30;을 잘 보면 let이나 var 없이 그냥 대입만 하고 있다. 이렇게 선언 키워드 없이 값을 대입하면, 자바스크립트는 자동으로 전역 스코프에 새 변수를 만들어버린다. 함수 안에서 썼다고 해서 지역변수가 되는 게 아니다.
그래서 함수가 끝난 뒤 바깥의 document.write("전역변수 z = " + z)에서 z가 문제없이 30을 출력한다. 코드를 짠 사람이 "z도 y처럼 함수 안에서만 쓰는 변수겠지"라고 생각했다면, 이건 의도와 다르게 동작하는 함정이다.
let(또는 const)으로 선언하는 습관이 중요하다.원본 코드 주석은 "var로 선언해도 동일"이라고 하지만, 이는 전역·지역 스코프 동작에 한해서다. if나 for 같은 블록 스코프에서는 둘의 동작이 갈린다.
if 블록 안
let b는 블록 밖에서 완전히 사라짐같은 이름 재선언 시 에러 발생 → 실수를 바로 알 수 있음
if 블록 안
var b는 블록 밖에서도 접근 가능(!)같은 이름 재선언해도 에러 없이 덮어씀 → 실수를 못 알아챔
- 블록 스코프가 명확해서 변수가 "새어나가는" 사고를 막는다
- 재선언 시 에러를 내서 오타·중복 실수를 코드 작성 시점에 잡아준다
- 값이 안 바뀌는 변수는
const로 선언해 더 안전하게 쓸 수 있다
| 실수 | 증상 | 해결 |
|---|---|---|
함수 안에서 let 없이 변수 = 값만 씀 |
지역변수인 줄 알았는데 전역변수가 되어버림 | 모든 변수는 let·const로 반드시 선언 후 사용 |
| if·for 블록 밖에서 블록변수 접근 | "변수명 is not defined" 에러 | 블록 밖에서도 필요한 값이면 블록 바로 위에서 변수 선언 |
| 함수 안팎에서 같은 이름을 지역·전역에 중복 사용 | 어느 값을 참조하는지 헷갈려 디버깅 지연 | 스코프가 다르면 이름도 다르게 지어 혼동 방지 |
var로 블록 스코프를 기대하고 코딩 |
블록 안 변수가 밖으로 새어나가 값이 덮어써짐 | 블록 스코프가 필요하면 무조건 let·const 사용 |
| 함수가 끝난 뒤 지역변수를 바깥에서 다시 참조 시도 | "is not defined" 에러 또는 undefined | 함수 실행 결과가 필요하면 return으로 값을 반환받아 사용 |
핵심 한 줄 요약
Tags
'php' 카테고리의 다른 글
| JavaScript 리터럴 — 숫자·불리언·문자열 완전 정리 (0) | 2026.07.03 |
|---|---|
| JavaScript 산술 연산 — +·-·*·/·% 완전 정리 (0) | 2026.07.02 |
| MySQL PROCEDURE SELECT — 특정 회원 조회 완전 정리 (0) | 2026.07.02 |
| MySQL BEFORE TRIGGER — 삽입 전 데이터 보정 · 트리거 체인 완전 정리 (0) | 2026.07.02 |
| MySQL PROCEDURE CURSOR — 행 단위 반복 처리 완전 정리 (1) | 2026.07.02 |
왕진 블로그

댓글