x is not a function — 원인·해결·예방
자바스크립트에서 무언가를 호출했더니 "Uncaught TypeError: x is not a function"이 뜬다. 해석하면 "x는 함수가 아닌데 함수처럼 호출했다"는 뜻이다. 이름 뒤에 ()를 붙여 실행하려 했는데, 정작 그 자리에 있던 값이 함수가 아니었던 것이다. 메서드 이름 오타, 라이브러리가 안 불러와진 상태, this가 엉뚱한 걸 가리켜 메서드를 못 찾는 경우, 배열 메서드를 배열이 아닌 값에 쓴 경우가 단골이다. 다행히 메시지가 친절해서 "무엇이 함수가 아닌지"를 그대로 알려준다. 이 글은 이 에러의 의미, 원인, 그리고 typeof 가드를 비롯한 해결·예방을 정리한다.

이 글의 구성
🔎 에러 메시지의 의미
이 에러는 TypeError의 한 종류다. 자바스크립트에서 어떤 값 뒤에 ()를 붙이면 "이걸 함수로 실행하라"는 뜻인데, 그 값이 실제로 호출 가능한 함수가 아니면 엔진이 "이건 함수가 아니다"라며 TypeError를 던진다. 숫자·문자열·객체·undefined 같은 값을 함수처럼 부르려 할 때 발생한다.
메시지가 꽤 구체적이다. obj.method is not a function이라면 obj.method가 함수가 아니라는 뜻이고, doSomething is not a function이라면 doSomething이 함수가 아니라는 신호다. 즉 () 바로 앞에 있던 그 이름이 함수가 아니었던 것이다. 무엇을 호출하려다 막혔는지 메시지가 정확히 짚어 주므로, 그 값의 정체부터 확인하면 된다.
핵심 — () 앞의 값이 함수가 아니었다
메시지의 "x"는 호출하려던 대상이다. 그 x가 undefined인지, 다른 타입의 값인지, 아니면 이름을 잘못 썼는지를 확인하는 게 첫걸음이다. console.log(typeof x)를 찍어 보면 "function"이 아닌 무엇이 들어 있는지 바로 드러난다.
🧩 자주 나오는 발생 원인 4가지
원인 1 — 메서드 이름 오타·대소문자
가장 흔하다. toLowerCase를 toLowercase로, getElementById를 getElementByID로 쓰는 식이다. 없는 이름으로 접근하면 그 값은 undefined가 되고, undefined를 호출하니 "is not a function"이 난다.
원인 2 — 변수에 함수가 아닌 값이 들어 있음
같은 이름의 변수가 함수를 덮어썼거나, 함수라고 생각한 값이 사실 숫자·문자열·객체인 경우다. 또 API 응답을 함수처럼 호출하거나, 함수를 반환할 줄 알았는데 값을 반환한 경우도 여기 해당한다.
원인 3 — 라이브러리 미로드·버전 차이
라이브러리가 안 불러와졌거나, 버전이 달라 그 메서드가 없거나 이름이 바뀐 경우다. 스크립트 순서가 틀려 라이브러리보다 내 코드가 먼저 실행되면 메서드를 못 찾아 호출에서 터진다.
원인 4 — 타입에 없는 메서드 호출
배열 메서드(map·forEach)를 배열이 아닌 값에 쓰거나, 유사 배열(arguments·일부 DOM 컬렉션)에 배열 메서드를 바로 호출하는 경우다. 그 타입에는 그런 메서드가 없어 함수가 아니라고 막힌다.
💻 재현과 진단
전형적인 재현이다. 메서드 이름 오타로 undefined를 호출하게 되는 경우다.
// toLowerCase 를 toLowercase 로 오타
const name = "Kim";
console.log(name.toLowercase());
// ✗ TypeError: name.toLowercase is not a function
// 정체 확인 — function 이 아니면 범인
console.log(typeof name.toLowercase); // "undefined"
진단의 핵심은 () 앞 값의 타입을 찍어 보는 것이다. typeof로 확인했을 때 "function"이 아니라 "undefined"·"object"·"string" 등이 나오면, 그 값이 왜 함수가 아닌지(오타·미로드·잘못된 값)를 추적하면 된다.
// 유사 배열(arguments)에 배열 메서드 → not a function
function sum() {
return arguments.map(n => n * 2); // arguments엔 map 없음
}
// ✗ TypeError: arguments.map is not a function
🛠 해결 방법과 안전 호출
원인별로 손볼 곳이 다르다. 대부분은 "정말 함수인지"를 확인하는 데서 풀린다.
| 원인 | 해결 |
|---|---|
| 오타 | 메서드 철자·대소문자 확인(toLowerCase 등), 자동완성 활용 |
| 함수 아님 | typeof x === "function" 가드, 그 값이 무엇인지 추적 |
| 미로드·버전 | 스크립트 순서·로드 확인, 라이브러리 버전별 메서드 존재 확인 |
| 유사 배열 | Array.from()·전개([...x])로 진짜 배열로 변환 후 메서드 호출 |
| this 손실 | 화살표 함수·bind로 this 고정(아래 섹션 참고) |
값이 함수일 수도 아닐 수도 있는 자리라면, 호출 전에 확인하거나 옵셔널 호출을 쓴다.
// ✓ 함수일 때만 호출
if (typeof callback === "function") {
callback();
}
// ✓ 옵셔널 호출 — 단, null/undefined 일 때만 건너뜀
obj.method?.();
여기서 옵셔널 호출 ?.()의 동작을 정확히 알아 둘 필요가 있다. obj.method?.()는 obj.method가 null이나 undefined일 때만 호출을 건너뛰고 undefined를 돌려준다. 만약 obj.method에 함수가 아닌 다른 값(숫자·문자열 등)이 들어 있다면, ?.()로도 막지 못하고 여전히 "is not a function"이 난다. 그래서 "없을 수도 있는 콜백"엔 ?.()가 알맞고, "값은 있는데 함수가 아닌" 상황까지 막으려면 typeof 검사가 필요하다.
⚖️ this 손실로 인한 경우
메서드 이름이 분명 맞는데도 이 에러가 난다면 this 문제일 수 있다. 객체의 메서드를 떼어내 콜백으로 넘기거나 다른 함수로 호출하면, 그 메서드 안의 this가 원래 객체를 잃어버려 내부에서 부르는 다른 메서드를 못 찾는다.
// 메서드를 떼어 콜백으로 넘기면 this 손실
const obj = {
value: 10,
show() { return this.getValue(); },
getValue() { return this.value; }
};
setTimeout(obj.show, 100);
// ✗ this가 obj가 아니게 되어 this.getValue is not a function
// ✓ bind 또는 화살표로 this 고정
setTimeout(obj.show.bind(obj), 100);
setTimeout(() => obj.show(), 100);
this 바인딩은 그 자체로 깊은 주제라 별도로 다루지만, 여기서 기억할 것은 하나다. "메서드 이름은 맞는데 not a function이라면 this가 엉뚱한 걸 가리키고 있지 않은지" 의심해 보는 것이다. bind나 화살표 함수로 this를 원래 객체에 고정하면 풀린다.
메시지가 "무엇이" 함수가 아닌지 짚어 준다. () 앞 값의 typeof부터 찍어라. 이름이 맞는데도면 this를 의심하라.
— 정말 함수인지부터 확인
💬 자주 묻는 질문 5가지
Q1분명 그 메서드가 있는데 왜 not a function이죠?
먼저 철자·대소문자를 확인하세요(toLowerCase vs toLowercase). 맞다면 그 값의 typeof를 찍어 보세요. "function"이 아니면 변수가 다른 값으로 덮였거나, 라이브러리가 안 불러와졌거나, this가 엉뚱한 걸 가리키는 경우입니다.
Q2이거랑 "Cannot read properties of undefined"는 뭐가 다른가요?
undefined의 속성을 읽으려 하면 "Cannot read properties of undefined"이고, 값을 함수로 호출하려는데 함수가 아니면 "is not a function"입니다. 다만 obj.method()에서 method가 undefined면 "obj.method is not a function"으로 나타나기도 합니다. 둘 다 결국 "그 자리에 기대한 게 없다"는 신호죠.
Q3map is not a function이 떠요.
대상이 진짜 배열이 아닐 가능성이 큽니다. arguments나 일부 DOM 컬렉션 같은 유사 배열, 또는 객체에 map을 호출하면 그 타입엔 map이 없어 막힙니다. Array.from()이나 전개 연산자([...x])로 진짜 배열로 바꾼 뒤 호출하세요. Array.isArray로 먼저 확인해도 좋습니다.
Q4?.() 만 붙이면 안전한가요?
부분적으로만 안전합니다. obj.method?.()는 method가 null이나 undefined일 때만 호출을 건너뜁니다. method에 함수가 아닌 다른 값(숫자·문자열 등)이 들어 있으면 ?.()로도 여전히 에러가 납니다. "값은 있는데 함수가 아닌" 경우까지 막으려면 typeof === "function" 검사를 쓰세요.
Q5라이브러리 메서드인데 not a function이에요.
라이브러리가 로드되기 전에 호출했거나, 버전이 달라 그 메서드가 없거나 이름이 바뀐 경우입니다. 스크립트 순서를 확인해 라이브러리를 먼저 로드하고, 사용 중인 버전의 문서에서 그 메서드가 실제로 존재하는지 확인하세요. CDN 로드 실패도 같은 증상을 만듭니다.
📌 결론
"x is not a function"은 함수가 아닌 값에 ()를 붙여 호출했을 때 나는 TypeError다. 메시지가 () 앞의 어떤 값이 함수가 아닌지 정확히 짚어 주므로, 그 값의 정체를 확인하는 데서 해결이 시작된다.
실무 원칙은 다음과 같다.
🧪 typeof부터 찍는다. () 앞 값의 typeof가 "function"이 아니면, 무엇이 들어 있는지(undefined·다른 타입)를 보고 원인을 좁힌다.
🔤 이름과 타입을 맞춘다. 메서드 철자·대소문자를 확인하고, 배열 메서드는 진짜 배열에만(Array.from으로 변환) 호출한다.
🔗 this와 로드를 의심한다. 이름이 맞는데도 나면 this 손실(bind·화살표로 고정)을, 라이브러리 메서드면 로드 순서·버전을 점검한다.
not a function 에러 체크리스트
본 글은 자바스크립트 TypeError(is not a function)의 일반적 원인과 해결 방법을 정리한 자료다. 코드 수정은 영향 범위를 확인한 뒤 신중히 적용한다.
#JavaScript #TypeError #isnotafunction #자바스크립트에러 #함수호출 #메서드오타 #this바인딩 #typeof #Arrayfrom #옵셔널호출 #프론트엔드 #JS디버깅 #런타임에러 #웹개발 #코딩초보
'IT' 카테고리의 다른 글
| Maximum call stack size exceeded — 무한 재귀 원인·해결 (0) | 2026.06.30 |
|---|---|
| Uncaught (in promise) — 처리 안 된 Promise 거부 원인·해결 (0) | 2026.06.30 |
| SyntaxError: Unexpected token — 원인·해결·예방 (0) | 2026.06.30 |
| ReferenceError: x is not defined — 원인·해결·예방 (1) | 2026.06.29 |
| Cannot read properties of undefined (reading 'x') — 원인·해결·예방 (0) | 2026.06.29 |
댓글