ReferenceError: x is not defined — 원인·해결·예방
자바스크립트 콘솔에서 두 번째로 자주 보는 빨간 줄이 이것이다. "Uncaught ReferenceError: x is not defined". 해석하면 "x라는 이름을 어디서도 찾을 수 없다"는 뜻이다. 그 변수나 함수가 접근 가능한 어떤 범위(스코프)에도 선언돼 있지 않을 때 터진다. 앞 글에서 다룬 undefined 에러와 헷갈리기 쉬운데, 둘은 결정적으로 다르다. undefined는 "이름은 있는데 값이 비었다", not defined는 "그 이름 자체가 없다"이다. 대부분 오타이거나, 스크립트·라이브러리가 안 불러와졌거나, 스코프를 벗어난 변수를 쓴 경우다. 이 글은 이 에러의 의미, undefined와의 차이, 원인과 해결을 정리한다.

이 글의 구성
🔎 에러 메시지의 의미
ReferenceError는 코드가 존재하지 않는 식별자(변수·함수 이름)를 참조하려 할 때 발생한다. 자바스크립트 엔진은 어떤 이름을 만나면 현재 스코프부터 바깥으로 차근차근 그 선언을 찾는데, 끝까지(전역 스코프까지) 가도 못 찾으면 "이런 이름은 정의된 적 없다"며 ReferenceError를 던진다.
메시지는 단순하다. x is not defined는 "x라는 이름이 정의돼 있지 않다"는 뜻이고, x 자리에 실제 못 찾은 이름이 들어간다. $ is not defined라면 $가, myFunc is not defined라면 myFunc가 어디에도 선언되지 않았다는 신호다. 즉 엔진이 그 이름의 출처를 찾지 못한 것이다.
핵심 — 이름 자체가 없다
ReferenceError는 "값이 비었다"가 아니라 "선언을 못 찾았다"는 신호다. 그래서 디버깅의 첫 질문은 단순하다. "이 이름을 내가 어딘가에 선언했나, 그리고 그 선언이 여기서 보이는 범위에 있나?" 둘 중 하나라도 아니면 이 에러가 난다.
⚖️ not defined vs undefined
이 에러를 이해하는 핵심은 undefined와의 구분이다. 메시지가 비슷해 보여도 상황이 정반대다.
| 구분 | x is not defined | undefined |
|---|---|---|
| 뜻 | 이름이 선언된 적 없음 | 선언은 됐으나 값이 없음 |
| 결과 | ReferenceError로 즉시 중단 | 에러 아님, 값이 undefined일 뿐 |
| 예 | console.log(abc) // 선언 없음 | let a; console.log(a) // undefined |
쉽게 말해, undefined는 "상자는 있는데 비었다", not defined는 "상자 자체가 없다"이다. let a;라고 선언만 하고 값을 안 넣으면 a는 undefined지만 에러는 아니다. 반면 어디에도 선언하지 않은 abc를 쓰면 "그런 상자 없다"며 ReferenceError가 난다. 이 구분을 잡으면 "값을 채워야 하는 문제(undefined)"인지 "선언·로드를 고쳐야 하는 문제(not defined)"인지가 갈린다.
🧩 자주 나오는 발생 원인 4가지
원인 1 — 변수·함수 이름 오타
가장 흔하다. userName을 username으로, getData를 getDate로 쓰는 식이다. 대소문자까지 구분하므로 한 글자만 달라도 "그런 이름 없다"가 된다. 선언한 이름과 쓰는 이름의 철자를 맞췄는지부터 본다.
원인 2 — 라이브러리·스크립트 미로드
$ is not defined(jQuery 미로드)나 외부 라이브러리 전역 변수가 안 잡히는 경우다. 스크립트 태그 순서가 틀렸거나, CDN 로드가 실패했거나, 내 코드가 라이브러리보다 먼저 실행된 것이다.
원인 3 — 스코프 밖의 변수 접근
함수 안에서 선언한 변수를 함수 밖에서 쓰거나, 블록 {} 안의 let·const를 블록 밖에서 참조하는 경우다. 선언은 분명 했는데 그게 "여기서 보이는 범위"에 없어서 못 찾는다.
원인 4 — 환경에 없는 전역 사용·import 누락
Node.js에서 window·document를 쓰거나(브라우저 전용), 모듈을 import하지 않고 그 이름을 쓰는 경우다. 실행 환경에 그 전역이 없거나, 가져오는 구문을 빠뜨려 이름이 정의되지 않는다.
💻 재현과 진단
전형적인 재현이다. 선언하지 않은 이름을 그대로 사용하면 즉시 터진다.
// 어디에도 선언하지 않은 이름 사용
console.log(userName);
// ✗ Uncaught ReferenceError: userName is not defined
// 오타 — 선언은 username, 사용은 userName
const username = "김개발";
console.log(userName); // 대소문자 불일치 → not defined
콘솔의 에러를 클릭하면 몇 번째 줄·어느 함수에서 났는지 스택 추적이 나온다. 그 줄에서 문제의 이름을 찾아, 같은 철자로 선언한 곳이 있는지 그리고 그 선언이 이 줄에서 보이는 스코프에 있는지 확인한다.
// 함수 안 변수를 밖에서 접근 → not defined
function load() {
const data = 42;
}
console.log(data);
// ✗ data is not defined (data는 load 안에서만 보임)
🛠 해결 방법과 안전 체크
ReferenceError는 "선언과 사용을 맞추는" 문제다. 원인별로 손볼 곳이 다르다.
| 원인 | 해결 |
|---|---|
| 오타 | 선언한 이름과 철자·대소문자 일치, 에디터 자동완성 활용 |
| 라이브러리 미로드 | 스크립트 순서 확인(라이브러리 먼저), CDN 로드 성공 여부 점검 |
| 스코프 밖 | 필요한 범위에 선언하거나 함수가 값을 return하도록 변경 |
| import 누락 | 상단에 import 구문 추가, 모듈 경로 확인 |
| 환경 불일치 | Node에서 window 등 브라우저 전역 사용 금지, 환경에 맞는 API로 |
값이 있을지 없을지 불확실한 이름을 안전하게 검사해야 한다면, typeof를 쓰면 된다. typeof는 선언되지 않은 이름에 써도 에러를 던지지 않는 특별한 연산자다.
// ✗ 선언 안 된 이름을 바로 검사하면 터짐
if (maybeGlobal) { ... } // ReferenceError 가능
// ✓ typeof 는 미선언 이름에도 안전 (에러 X)
if (typeof maybeGlobal !== "undefined") {
console.log(maybeGlobal);
}
한 가지 구분해 둘 것이 있다. let·const로 선언한 변수를 선언 줄보다 위에서 쓰면 비슷해 보이는 에러가 나는데, 그 메시지는 크롬·Node 기준 "Cannot access 'x' before initialization"으로 다르다(파이어폭스·사파리는 문구가 조금씩 다르지만 모두 ReferenceError다). 이건 이름은 존재하지만 아직 초기화 전 구간(TDZ)이라 막힌 경우다. 반면 "x is not defined"는 이름 자체가 없는 것이라, 둘은 원인이 다르다.
undefined는 상자가 비었고, not defined는 상자가 없다. 전자는 값을, 후자는 선언과 로드를 고쳐라.
— 이름을 찾을 수 있는 범위에 선언했는가
💬 자주 묻는 질문 5가지
Q1undefined랑 not defined가 헷갈려요.
undefined는 "선언은 됐는데 값이 비었다"이고, not defined는 "이름 자체가 선언된 적 없다"입니다. 전자는 에러가 아니라 값일 뿐이고, 후자는 ReferenceError로 코드가 멈춥니다. 상자는 있는데 비었나(undefined), 상자가 없나(not defined)로 기억하세요.
Q2$ is not defined가 떠요.
jQuery 같은 라이브러리가 안 불러와진 상태에서 $를 쓴 것입니다. 스크립트 태그 순서를 확인해 라이브러리를 내 코드보다 먼저 로드하고, CDN 주소가 살아 있는지(네트워크 탭에서 로드 성공 여부) 점검하세요. 내 코드가 라이브러리보다 먼저 실행되면 같은 에러가 납니다.
Q3분명 선언했는데 not defined가 나요.
스코프 문제일 가능성이 큽니다. 함수나 블록 안에서 선언한 변수는 그 밖에서 보이지 않습니다. 선언이 사용하는 위치에서 접근 가능한 범위에 있는지 확인하세요. 값을 밖으로 꺼내야 한다면 함수가 return하도록 바꾸거나, 더 바깥 스코프에 선언합니다.
Q4존재할지 모르는 전역을 안전하게 검사하려면?
typeof를 쓰세요. typeof는 선언되지 않은 이름에 사용해도 에러를 던지지 않는 특별한 연산자라, typeof x !== "undefined"로 안전하게 존재 여부를 확인할 수 있습니다. 이름을 바로 if 조건에 넣으면 미선언일 때 ReferenceError가 날 수 있습니다.
Q5"Cannot access before initialization"은 같은 거예요?
비슷해 보이지만 다릅니다. 그건 let·const로 선언한 이름을 선언 줄보다 위에서 썼을 때 나는 메시지로, 이름은 존재하지만 초기화 전 구간(TDZ)이라 막힌 것입니다. "x is not defined"는 이름 자체가 없는 경우죠. 전자는 선언을 위로 올리거나 사용을 아래로, 후자는 선언·로드를 점검합니다.
📌 결론
"ReferenceError: x is not defined"는 선언된 적 없는 이름을 참조할 때 나는 에러다. undefined가 "상자는 있는데 비었다"라면, not defined는 "상자 자체가 없다"이다. 그래서 값을 채우는 문제가 아니라, 선언과 로드·스코프를 맞추는 문제다.
실무 원칙은 다음과 같다.
🔤 이름부터 맞춘다. 선언한 철자와 사용하는 철자가 대소문자까지 같은지 본다. 오타가 이 에러의 1순위 원인이다.
📦 스코프를 확인한다. 함수·블록 안에 선언한 이름은 밖에서 안 보인다. 사용 위치에서 접근 가능한 범위에 선언했는지 점검하고, 안전 검사엔 typeof를 쓴다.
🔗 로드와 import를 점검한다. 라이브러리는 내 코드보다 먼저, 모듈은 import 구문으로, 환경에 없는 전역(Node의 window 등)은 쓰지 않는다.
not defined 에러 체크리스트
본 글은 자바스크립트 ReferenceError의 일반적 원인과 해결 방법을 정리한 자료다. 코드 수정은 영향 범위를 확인한 뒤 신중히 적용한다.
#JavaScript #ReferenceError #notdefined #자바스크립트에러 #변수선언 #스코프 #호이스팅 #typeof #jQuery #스크립트로드 #import #프론트엔드 #JS디버깅 #런타임에러 #코딩초보
'IT' 카테고리의 다른 글
| x is not a function — 원인·해결·예방 (0) | 2026.06.30 |
|---|---|
| SyntaxError: Unexpected token — 원인·해결·예방 (0) | 2026.06.30 |
| Cannot read properties of undefined (reading 'x') — 원인·해결·예방 (0) | 2026.06.29 |
| HTTP 상태 코드 완전 정리 — 1xx~5xx 분류와 4xx·5xx 차이 (1) | 2026.06.28 |
| Mixed Content 에러 — 혼합 콘텐츠·HTTPS 속 HTTP 차단 원인·해결 (0) | 2026.06.28 |
댓글