본문 바로가기
IT

ReferenceError: x is not defined — 원인·해결·예방

by 샤나엘 2026. 6. 29.
반응형

ReferenceError: x is not defined — 원인·해결·예방

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

ReferenceError: x is not defined

 

이 글의 구성

 

🔎에러 메시지의 의미
⚖️not defined vs undefined
🧩자주 나오는 발생 원인 4가지
💻재현과 진단
🛠해결 방법과 안전 체크
💬자주 묻는 질문 5가지

🔎 에러 메시지의 의미

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 에러 체크리스트

 

01선언한 이름 vs 사용하는 이름의 철자·대소문자 일치 확인.
02스택 추적으로 어느 줄·함수에서 났는지 확인.
03선언이 사용 위치에서 보이는 스코프에 있는지 점검.
04라이브러리·스크립트 로드 순서·성공 여부 확인.
05모듈 import 누락·환경(Node/브라우저) 전역 불일치 점검.
06불확실한 전역은 typeof x !== "undefined"로 안전 검사.

본 글은 자바스크립트 ReferenceError의 일반적 원인과 해결 방법을 정리한 자료다. 코드 수정은 영향 범위를 확인한 뒤 신중히 적용한다.

 

#JavaScript #ReferenceError #notdefined #자바스크립트에러 #변수선언 #스코프 #호이스팅 #typeof #jQuery #스크립트로드 #import #프론트엔드 #JS디버깅 #런타임에러 #코딩초보

반응형

댓글