본 문서는 BeFit 프로젝트의 **AI 분석 모듈(befit-ai.js)**이 특정 DOM 요소가 없는 페이지에서 로드될 때 발생하는 Cannot read properties of null 오류의 원인 및 해결 과정을 정리한 기술 문서입니다.
작성자: 왕택준
작성일: 2025년 6월 27일
-
에러 메시지:
Uncaught TypeError: Cannot read properties of null (reading 'age')(또는...reading 'value',...reading 'addEventListener'등 다양한 속성으로 발생) -
에러 콜 스택:
initEventListeners @ befit-ai.js:100 main @ befit-ai.js:152 (anonymous) @ befit-ai.js:163 -
발생 페이지:
index.html을 제외한 모든 페이지 (befit-ai.html,playlist.html,shopping.html) -
발생 배경: AI 분석 기능(폼 요소)이 없는 일반 페이지에서
/src/befit-ai/befit-ai.js모듈이 실행될 때 -
상세 설명:
befit-ai.js는 페이지 로드 시 특정 ID(dietForm-befit-ai)를 가진 폼과 그 하위 요소들이 반드시 존재한다고 가정하고 동작합니다. 콜 스택에서 볼 수 있듯, 메인 로직(main)이 이벤트 리스너를 초기화하는initEventListeners함수를 호출할 때, 이 함수 내에서 존재하지 않는 DOM 요소를 참조하여null이 반환되고, 해당null값의 속성(age등)에 접근하려다 런타임 에러가 발생합니다.
문제의 근본 원인은 모듈의 의존성과 방어 코드 부재에 있습니다.
- DOM 의존성: 모듈 로직 전체가
dietForm-befit-ai폼과 그 하위 요소들(예:age입력 필드)의 존재를 전제로 설계되었습니다. null참조 발생:initEventListeners함수 내에서document.getElementById('age-input')과 같은 코드가null을 반환합니다.null에 대한 속성 접근: 이null값에 대해.value나.addEventListener같은 속성/메서드에 접근하면서TypeError가 발생하고, 스크립트 실행이 즉시 중단됩니다. 에러 메시지의(reading 'age')는 아마도form.elements.age와 같이 객체의 속성으로 DOM 요소에 접근하려다 발생한 것으로 추정됩니다.
- 각 함수/이벤트 리스너 내부에 개별적으로
if (element)와 같은 null 체크를 추가하는 방법을 초기에 고려하였으나, 이 방식은 조건문 중복, 코드 가독성 저하, 추후 유지보수 난이도 상승 등의 문제가 있음을 확인하였습니다.
// /src/befit-ai/befit-ai.js
function main() {
// 모듈의 핵심 의존성인 폼 요소를 찾습니다.
const dietForm = document.getElementById('dietForm-befit-ai');
// Guard Clause: 모듈 실행에 필수적인 폼 요소가 없으면 실행을 즉시 중단합니다.
if (!dietForm) {
// console.log("AI 분석 폼이 없는 페이지이므로 초기화를 건너뜁니다.");
return;
}
// --- 아래 코드는 dietForm이 존재하는 것이 보장된 상태에서만 실행됩니다 ---
initEventListeners(dietForm); // dietForm을 인자로 전달하여 중복 탐색 방지
Utils.toggleBMRMode();
Storage.updateShowSavedResultBtnVisibility();
}
// DOM이 완전히 로드된 후 메인 로직을 실행합니다.
document.addEventListener("DOMContentLoaded", main);- 핵심 해결책 (Guard Clause):
main함수의 가장 앞단에서if (!dietForm) return;조건을 추가했습니다. 이 한 줄로 인해, AI 분석 폼이 없는 페이지에서는initEventListeners함수 자체가 호출되지 않아 오류가 원천 차단됩니다. - 안전장치 (
DOMContentLoaded): DOM 요소를 참조하기 전에 문서가 준비될 때까지 기다리게 함으로써, 스크립트 실행 시점과 관련된 잠재적 오류를 추가로 방지합니다.
- 문제: 특정 페이지의 DOM 요소에 강하게 의존하는 공용 모듈은, 다른 페이지에서 로드될 때 다양한 형태의
null참조 오류를 일으키기 쉽습니다. - 해결: 모듈의 진입점에서 Guard Clause(가드 클로즈) 패턴을 사용하여 자신의 실행 환경을 스스로 검사하고, 조건이 맞지 않으면 조용히 실행을 종료하는 방어적 초기화(Defensive Initialization) 구조를 적용했습니다.
- 배운 점: 모듈을 설계할 때, "필요한 요소가 언제나 존재할 것"이라고 가정해서는 안 됩니다. 모든 페이지에서 안전하게 임포트될 수 있도록, 자신의 실행 여부를 스스로 결정하는 독립적이고 방어적인 구조를 갖추는 것이 견고한 웹 애플리케이션의 핵심임을 깨달았습니다.
본 문서는 특정 DOM에 의존하는 공용 모듈의 null 참조 오류를 방지하기 위한 구조적 개선 사례를 기록한 기술 문서입니다.