안녕하세요, 코딩하는곰입니다! 자바스크립트 개발을 하다 보면 다양한 에러를 마주하게 되는데, 그중에서도 “Object is not extensible” 에러는 객체의 확장을 막는 메서드들을 사용할 때 자주 발생합니다. 이 에러는 객체에 새로운 속성을 추가하려고 할 때 나타나며, 특히 Object.freeze(), Object.seal(), Object.preventExtensions() 같은 메서드로 객체를 보호한 경우에 발생합니다. 이번 포스팅에서는 이 에러의 원인을 깊이 있게 파헤치고, 해결 방법부터 예방 전략까지 상세하게 알아보겠습니다. 자바스크립트로 개발하는 모든 분들께 도움이 되는 내용이니, 끝까지 읽어주세요!
🎮 게임 개발에 관심이 있다면, (자바 기초) 변수 선언과 초기화 완벽 가이드 - 자료형부터 작명법까지를 참고해보세요.
“Object is not extensible” 에러는 자바스크립트에서 객체가 확장 불가능한 상태일 때, 새로운 속성을 추가하려고 시도하면 발생하는 TypeError입니다. 이 에러의 근본적인 원인은 객체가 “확장”될 수 없도록 설정되었기 때문인데, 여기서 “확장”이란 객체에 새로운 속성을 동적으로 추가하는 것을 의미합니다. 자바스크립트에서는 객체의 확장을 제어하는 몇 가지 메서드를 제공하는데, 대표적으로 Object.freeze(), Object.seal(), Object.preventExtensions()가 있습니다. 이러한 메서드들을 사용하면 객체의 상태를 보호할 수 있지만, 실수로 새로운 속성을 추가하려고 하면 에러가 발생하게 됩니다.
에러가 발생하는 구체적인 시나리오를 살펴보겠습니다. 예를 들어, Object.preventExtensions() 메서드를 사용하여 객체를 확장 불가능하게 만든 후, 새로운 속성을 추가하려고 하면 에러가 발생합니다. 이는 엄격 모드(strict mode)에서 특히 두드러지는데, 엄격 모드가 아닌 경우에는 에러가 발생하지 않고 단순히 작업이 무시될 수 있습니다. 하지만 현대 자바스크립트 개발에서는 대부분 엄격 모드를 사용하므로, 에러를 맞이할 가능성이 높습니다.
'use strict';const obj = { name: '곰' };Object.preventExtensions(obj);obj.age = 5; // TypeError: Cannot add property age, object is not extensible
위 코드에서 Object.preventExtensions(obj)를 호출하여 obj 객체를 확장 불가능하게 만들었습니다. 그 후 obj.age = 5를 시도하면 “Object is not extensible” 에러가 발생합니다. 이는 객체의 확장이 금지되었음을 나타내며, 개발자에게 객체의 구조를 변경하지 말라는 신호를 보내는 것입니다.
에러의 원인을 정리하자면, 주로 다음과 같은 상황에서 발생합니다:
Object.freeze(), Object.seal(), Object.preventExtensions()로 객체를 처리한 후 새로운 속성을 추가하려고 할 때'use strict'를 사용하는지 확인하는 것이 중요합니다. 엄격 모드는 자바스크립트의 오류를 더 엄격하게 검사하여 실수를 미리 잡아주는데, “Object is not extensible” 에러도 그중 하나입니다. 따라서 개발 과정에서 엄격 모드를 활성화하면 예기치 않은 객체 수정을 방지하는 데 도움이 됩니다.
마지막으로, 이 에러는 디버깅이 비교적 간단한 편에 속합니다. 대부분의 경우 에러 스택 트레이스를 통해 어떤 객체에서 문제가 발생했는지 쉽게 추적할 수 있습니다. 하지만 프로젝트가 커지고 외부 라이브러리를 사용하는 경우에는 객체가 어디서 봉인되었는지 찾기 어려울 수 있으니, 주의가 필요합니다.
⚡ 개발 실력을 향상시키고 싶다면, (MySQL/MariaDB 전문가가 설명하는) DBMS와 RDBMS의 차이 - 데이터베이스 구조의 핵심 이해를 참고해보세요.
“Object is not extensible” 에러를 완전히 이해하려면 자바스크립트의 객체 보호 메서드인 Object.freeze(), Object.seal(), Object.preventExtensions()의 차이점과 동작 방식을 자세히 알아야 합니다. 이 메서드들은 모두 객체의 변경을 제한하지만, 그 수준과 영향이 다릅니다. 각 메서드가 어떤 제한을 가하는지 구체적으로 살펴보고, 에러가 발생하는 상황을 예제 코드와 함께深入게 분석해 보겠습니다.
가장 기본적인 객체 보호 메서드로, 객체에 새로운 속성을 추가하는 것을 방지합니다. 하지만 기존 속성의 값 수정이나 삭제는 가능합니다. 이 메서드를 사용한 객체는 “확장 불가능”하게 되며, 새로운 속성을 추가하려고 하면 “Object is not extensible” 에러가 발생합니다.
'use strict';const obj = { name: '곰', age: 10 };Object.preventExtensions(obj);// 새로운 속성 추가 시도 - 에러 발생obj.job = 'developer'; // TypeError: Cannot add property job, object is not extensible// 기존 속성 수정은 가능obj.name = '코딩하는곰'; // 성공// 기존 속성 삭제도 가능delete obj.age; // 성공console.log(obj); // { name: '코딩하는곰' }
Object.preventExtensions()는 객체의 확장만 막을 뿐, 값 수정이나 속성 삭제는 허용합니다. 따라서 객체의 구조를 고정시키지만 내용은 변경할 수 있는 유연성을 제공합니다. 이 메서드는 객체의 기본 구조를 유지하면서도 내부 데이터는 동적으로 조작해야 하는 상황에 유용합니다.
Object.seal()은 Object.preventExtensions()보다 더 강력한 보호를 제공합니다. 이 메서드는 객체를 “봉인”하여 새로운 속성 추가를 방지하는 동시에 기존 속성의 삭제도 막습니다. 하지만 기존 속성의 값 수정은 여전히 가능합니다.
'use strict';const obj = { name: '곰', age: 10 };Object.seal(obj);// 새로운 속성 추가 시도 - 에러 발생obj.job = 'developer'; // TypeError: Cannot add property job, object is not extensible// 기존 속성 삭제 시도 - 에러 발생delete obj.age; // TypeError: Cannot delete property 'age' of #<Object>// 기존 속성 수정은 가능obj.name = '코딩하는곰'; // 성공console.log(obj); // { name: '코딩하는곰', age: 10 }
Object.seal()을 사용하면 객체의 구조가 완전히 고정됩니다. 새로운 속성을 추가할 수 없고 기존 속성을 삭제할 수도 없지만, 속성 값은 변경할 수 있습니다. 이는 객체의 기본 구조를 보존해야 하지만 내부 값은 업데이트해야 하는 경우에 적합합니다.
가장 강력한 객체 보호 메서드로, 객체를 “동결”하여 완전한 불변성을 부여합니다. Object.freeze()는 새로운 속성 추가와 기존 속성 삭제를 방지할 뿐만 아니라 기존 속성의 값 수정도 막습니다. 즉, 객체를 완전히 읽기 전용으로 만듭니다.
'use strict';const obj = { name: '곰', age: 10 };Object.freeze(obj);// 새로운 속성 추가 시도 - 에러 발생obj.job = 'developer'; // TypeError: Cannot add property job, object is not extensible// 기존 속성 수정 시도 - 에러 발생obj.name = '코딩하는곰'; // TypeError: Cannot assign to read only property 'name' of object '#<Object>'// 기존 속성 삭제 시도 - 에러 발생delete obj.age; // TypeError: Cannot delete property 'age' of #<Object>console.log(obj); // { name: '곰', age: 10 } - 변경 없음
Object.freeze()는 객체를 완전히 불변으로 만들어야 할 때 사용됩니다. React나 Redux와 같은 라이브러리에서 상태 불변성을 유지해야 하는 경우나, 설정 객체처럼 런타임 중 변경되면 안 되는 데이터를 다룰 때 유용합니다.
'use strict';const obj = {name: '곰',details: { age: 10, job: 'developer' }};Object.freeze(obj);// 직접 속성 수정 시도 - 에러 발생obj.name = '코딩하는곰'; // TypeError// 중첩 객체 수정은 가능obj.details.age = 20; // 성공console.log(obj.details); // { age: 20, job: 'developer' }
위 예제에서 obj 객체는 동결되었지만, obj.details 중첩 객체는 여전히 수정 가능합니다. 중첩 객체까지 완전히 보호하려면 깊은 동결(deep freeze)을 구현해야 합니다.
이처럼 객체 보호 메서드는 각기 다른 수준의 불변성을 제공하며, “Object is not extensible” 에러는 주로 이러한 메서드들이 적용된 객체를 변경하려고 할 때 발생합니다. 다음 섹션에서는 이러한 에러를 해결하고 예방하는 실제적인 방법들을 알아보겠습니다.
계정 보안을 강화하려면 무작위 비밀번호 생성기를 통해 안전한 비밀번호를 만드는 것이 중요합니다.
“Object is not extensible” 에러를 마주했을 때 당황하지 않고 효과적으로 해결하려면 체계적인 접근이 필요합니다. 이 섹션에서는 에러를 디버깅하는 방법부터 실전에서 바로 적용할 수 있는 해결책, 그리고 에러를 미리 방지하는 예방 전략까지 상세하게 설명하겠습니다. 자바스크립트 개발자로서 이러한 에러 처리 능력을 키운다면 더 견고한 코드를 작성할 수 있을 것입니다.
에러가 발생했을 때 가장 먼저 해야 할 일은 에러의 원인이 된 객체가 어떤 보호 메서드에 의해 처리되었는지 확인하는 것입니다. 자바스크립트에서는 Object.isExtensible(), Object.isSealed(), Object.isFrozen() 메서드를 사용하여 객체의 현재 상태를 확인할 수 있습니다.
const obj = { name: '곰' };console.log(Object.isExtensible(obj)); // true - 확장 가능console.log(Object.isSealed(obj)); // false - 봉인되지 않음console.log(Object.isFrozen(obj)); // false - 동결되 지 않음Object.preventExtensions(obj);console.log(Object.isExtensible(obj)); // false - 확장 불가능console.log(Object.isSealed(obj)); // false - 봉인되지 않음console.log(Object.isFrozen(obj)); // false - 동결되지 않음Object.seal(obj);console.log(Object.isExtensible(obj)); // false - 확장 불가능console.log(Object.isSealed(obj)); // true - 봉인됨console.log(Object.isFrozen(obj)); // false - 동결되지 않음Object.freeze(obj);console.log(Object.isExtensible(obj)); // false - 확장 불가능console.log(Object.isSealed(obj)); // true - 봉인됨console.log(Object.isFrozen(obj)); // true - 동결됨
이러한 확인 메서드를 사용하면 에러 발생 시 객체의 정확한 상태를 파악할 수 있습니다. 디버깅 과정에서 콘솔에 이러한 확인 코드를 추가하여 객체가 언제, 어떻게 보호되었는지 추적할 수 있습니다.
'use strict';// 올바른 접근: 보호 전에 모든 속성 추가const obj = {name: '곰',age: 10,job: 'developer' // 필요한 모든 속성을 미리 추가};Object.freeze(obj);// 이후에는 속성 추가 시도하지 않음
'use strict';const frozenObj = Object.freeze({ name: '곰', age: 10 });// 객체 복사본 생성하여 수정const modifiedObj = { ...frozenObj, job: 'developer' };console.log(modifiedObj); // { name: '곰', age: 10, job: 'developer' }// 또는 Object.assign() 사용const anotherCopy = Object.assign({}, frozenObj, { age: 20 });console.log(anotherCopy); // { name: '곰', age: 20 }
'use strict';const obj = Object.freeze({ name: '곰' });// 안전한 속성 추가 함수function safePropertyAdd(target, property, value) {if (Object.isExtensible(target)) {target[property] = value;return true;} else {console.warn('객체에 속성을 추가할 수 없습니다. 객체가 확장 불가능합니다.');return false;}}safePropertyAdd(obj, 'age', 10); // 경고 메시지 출력 후 false 반환
'use strict';const frozenObj = Object.freeze({name: '곰',details: { age: 10, job: 'developer' }});// 깊은 복사 함수function deepCopy(obj) {return JSON.parse(JSON.stringify(obj));}const newObj = deepCopy(frozenObj);newObj.details.age = 20; // 성공newObj.job = 'designer'; // 성공console.log(newObj); // { name: '곰', details: { age: 20, job: 'developer' }, job: 'designer' }
'use strict';const obj = { name: '곰' };Object.preventExtensions(obj);// Proxy를 사용하여 에러 처리 개선const handler = {set(target, property, value) {if (!Object.isExtensible(target)) {console.warn(`속성 ${property}을(를) 추가할 수 없습니다. 객체가 확장 불가능합니다.`);return false; // 에러 대신 false 반환}target[property] = value;return true;}};const proxyObj = new Proxy(obj, handler);proxyObj.age = 10; // 경고 메시지 출력, 에러 발생하지 않음
'use strict';// 설정 객체는 런타임 중 변경되지 않아야 함const APP_CONFIG = Object.freeze({apiUrl: 'https://api.example.com',timeout: 5000,retryCount: 3});// 의도적으로 보호된 객체임을 주석으로 설명
// 객체 상태 확인 유틸리티const objectStatus = {check(obj) {return {isExtensible: Object.isExtensible(obj),isSealed: Object.isSealed(obj),isFrozen: Object.isFrozen(obj)};},log(obj) {const status = this.check(obj);console.log('객체 상태:', status);}};const obj = Object.freeze({ name: '곰' });objectStatus.log(obj); // 객체 상태: {isExtensible: false, isSealed: true, isFrozen: true}
// Jest를 사용한 테스트 예제test('설정 객체는 동결되어야 한다', () => {expect(Object.isFrozen(APP_CONFIG)).toBe(true);});test('동결된 객체에 속성 추가 시도 시 에러 발생', () => {expect(() => {APP_CONFIG.newProperty = 'value';}).toThrow(TypeError);});
Object.freeze()로 동결하기Object.seal()로 봉인하기Object.preventExtensions()로 확장 막기
이러한 해결 방법과 예방 전략을 적용하면 “Object is not extensible” 에러를 효과적으로 처리하고, 더 안정적인 자바스크립트 애플리케이션을 개발할 수 있습니다. 객체의 불변성을 적절히 활용하면 버그를 줄이고 코드의 예측 가능성을 높일 수 있습니다.
논리적 사고와 문제 해결 능력을 기르고 싶다면, 다양한 난이도의 스도쿠를 제공하는 스도쿠 저니를 설치해보세요.
지금까지 자바스크립트의 “Object is not extensible” 에러에 대해 깊이 있게 알아보았습니다. 이 에러는 객체의 확장을 막는 메서드들을 사용할 때 발생하며, Object.freeze(), Object.seal(), Object.preventExtensions()의 차이점을 이해하는 것이 해결의 첫걸음입니다. 에러를 마주쳤을 때는 객체의 상태를 확인하고, 필요한 경우 복사본을 생성하거나 조건부 처리를 통해 유연하게 대응할 수 있습니다. 또한 예방 차원에서 의도적인 객체 보호 전략을 수립하고 테스트 코드를 활용하면 더 견고한 애플리케이션을 개발할 수 있습니다. 자바스크립트의 객체 불변성 개념은 처음에는 어려울 수 있지만, 익숙해지면 강력한 도 구가 될 것입니다. 코딩하는곰과 함께 자바스크립트 마스터로 성장하시길 응원합니다! 질문이나 추가로 궁금한 점이 있다면 댓글로 남겨주세요. 다음 포스팅에서 또 만나요!
로또 번호를 과학적으로 접근하고 싶다면, AI 분석과 통계 기반 번호 추천 앱 지니로또AI가 최적의 도구입니다.
