LogoSEO Jing
  • All Posts
  • SEO Jing
  • KD Team
  • CLab CoreTeam
  • Study

Contact Me

© 2026 SEOJing. All rights reserved.

프론트엔드스터디JavaScript프로토타입불변성타입체크

프론트엔드 스터디 7주차: 불변성, 프로토타입, 타입 체크

2026년 5월 11일·22분 읽기

7주차 학습 자료

  • 입문 강의 (처음이라면): 얄코 JS 입문 강의 클래스 챕터
  • 강의 스킵 가능: 아래 스킵 진단 문제 10개를 모두 맞히면 강의 시청 스킵 가능합니다.
  • 심화 자료 (딥다이브 대비):

    딥다이브 요약 GitHub

안녕하세요. 7주차입니다. 이번 주는 다른 언어 경험자에게 JS가 가장 낯설게 느껴지는 구간입니다. 프로토타입은 Java나 Python의 클래스 상속과 근본적으로 다른 JS만의 상속 방식이고, 불변성은 const를 써도 왜 완전히 불변이 아닌지를 이해하는 개념입니다. 타입 체크는 동적 타입 언어에서 런타임 안전성을 확보하는 방법입니다.


스킵 진단 문제

아래 10문제를 막힘없이 풀 수 있다면,

이번 주 학습 자료를 생략하거나, 모르는 부분만 선택적으로 읽으셔도 좋습니다.

바로 하단의 더 알면 좋을 것들을 확인해보세요.

Quiz1 / 10
Q.const로 선언한 객체에서 할 수 없는 것은 무엇일까요?

1. 불변성(Immutability) — const는 불변이 아니다

많은 분들이 const를 쓰면 값이 변하지 않는다고 오해합니다. 하지만 const는 변수가 가리키는 참조(주소)를 고정할 뿐, 그 주소에 있는 객체 내부 변경은 막지 않습니다.

js
const obj = { x: 1 };
obj.x = 99; // 가능 — 내부 프로퍼티 변경
obj.y = 100; // 가능 — 프로퍼티 추가
delete obj.x; // 가능 — 프로퍼티 삭제

obj = {}; // TypeError — 재할당만 불가

얕은 복사 vs 깊은 복사

객체를 복사할 때도 주의가 필요합니다. spread(...)나 Object.assign()은 얕은 복사 (shallow copy)로, 1단계 깊이만 새로운 값으로 복사됩니다. 중첩 객체는 여전히 참조를 공유합니다.

js
const original = { a: 1, nested: { b: 2 } };

// 얕은 복사
const shallow = { ...original };
shallow.a = 99; // original.a 영향 없음
shallow.nested.b = 99; // original.nested.b도 99로 바뀜!

// 깊은 복사 (간단한 방법 — 함수/undefined 등은 사라짐)
const deep = JSON.parse(JSON.stringify(original));
deep.nested.b = 999 

Object.freeze() — 진짜 불변 만들기

js
const obj = Object.freeze({ x: 1, nested: { y: 2 } });

obj.x = 99; // 무시됨 (strict mode에서는 TypeError)
obj.nested.y = 99; // 가능! — freeze는 최상위만 동결

// 완전한 불변이 필요하면 재귀적으로 freeze해야 함
function deepFreeze(obj) {
  Object.keys(obj).forEach((key) => {
    if ( objkey    objkey   

실무에서는 상태를 직접 변경하지 않고 새 객체를 만들어 반환하는 불변 패턴을 많이 사용합니다. React의 상태 관리(setState, useState)가 이 방식을 따릅니다.


2. 프로토타입 — JS의 상속 방식

Java나 Python은 클래스 기반 상속입니다. 클래스를 정의하고 extends로 상속합니다. JS는 다릅니다. 프로토타입 기반 상속 으로, 객체가 다른 객체를 직접 상속합니다. ES6의 class 문법도 내부적으로는 프로토타입을 사용합니다.

프로토타입 체인

모든 JS 객체는 [[Prototype]]이라는 내부 슬롯을 가지며, 이 슬롯이 상위 프로토타입 객체를 가리킵니다. 프로퍼티를 참조할 때 자신에게 없으면 프로토타입 체인을 따라 상위로 탐색합니다.

js
const obj = { x: 1 };

// obj에는 toString이 없지만 사용 가능
console.log(obj.toString()); // "[object Object]"

// 프로토타입 체인: obj → Object.prototype → null
// toString은 Object.prototype에 있음

생성자 함수와 prototype

js
function Person(name) {
  this.name = name;
  // 여기에 메서드를 넣으면 인스턴스마다 함수가 복사됨 — 비효율
}

// prototype에 메서드를 추가하면 모든 인스턴스가 공유
Person.prototype.greet = function () {
  console.log(`안녕하세요, ${this.name}입니다.`);
};

const p1 = new Person("철수");
const p2 = new 

[[Prototype]] vs prototype — 헷갈리는 두 개념

  • [[Prototype]]: 모든 객체가 가지는 내부 슬롯. 상위 프로토타입을 가리킴. __proto__로 접근 가능 (권장 안 함)
  • prototype: 함수 객체만 가지는 프로퍼티. new로 인스턴스를 만들 때 인스턴스의 [[Prototype]]이 됨
js
function Foo() {}

const foo = new Foo();

console.log(foo.__proto__ === Foo.prototype); // true
console.log(Foo.prototype.constructor === Foo); // true

원시값에서 메서드가 동작하는 이유

js
"hello".toUpperCase(); // "HELLO"
(42).toFixed(2); // "42.00"

// 원시값은 객체가 아닌데 어떻게 메서드가 있을까?
// JS 엔진이 메서드 호출 시 임시로 래퍼 객체(String, Number)로 변환
// 메서드 실행 후 래퍼 객체는 즉시 제거됨

3. 타입 체크 — typeof의 한계와 대안

정적 타입 언어(Java, TypeScript)에서는 컴파일 타임에 타입 오류를 잡아줍니다. 순수 JS는 런타임에야 타입이 결정되므로, 직접 확인이 필요한 경우가 있습니다.

typeof의 한계

js
typeof 1; // 'number'
typeof "hello"; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof function () {}; // 'function'

// 한계: 아래는 모두 'object'를 반환
typeof null; // 'object' ← 버그
typeof []; // 'object'
typeof {}; // 'object'
typeof new Date(); // 'object'

정확한 타입 확인: Object.prototype.toString.call()

js
function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1);
}

getType(1); // 'Number'
getType("hello"); // 'String'
getType(null); // 'Null'
getType([]); // 'Array'
getType({}); // 'Object'
getType(  

실무에서 자주 쓰는 타입 체크 패턴

js
// 배열 확인 — Array.isArray() 권장
Array.isArray([]);        // true
Array.isArray({});        // false

// null 확인 — === 사용
value === null

// null 또는 undefined 확인
value == null             // null과 undefined 모두 해당 (예외적으로 == 허용)

// 특정 인스턴스 확인 — instanceof
new Date() instanceof Date  // true
[] instanceof Array          // true
[] instanceof Object         // true (체인 전체 탐색)

TypeScript를 사용하면 이런 런타임 타입 체크의 대부분을 컴파일 타임으로 옮길 수 있습니다. React 프로젝트에서 TypeScript가 사실상 표준인 이유 중 하나입니다.


📝 학습 이해 퀴즈

아래 코드를 브라우저 콘솔에서 직접 실행해보고 결과를 입력해보세요.

Quiz1 / 3
Q.아래 코드에서 마지막 console.log의 출력 결과는?
js
const obj = Object.freeze({ x: 1, nested: { y: 2 } });
obj.x = 99;
obj.nested.y = 99;
console.log(obj.x, obj.nested.y);

📝 7주차 스터디 인증 미션

아래 질문 중 하나를 직접 찾아보고 답을 댓글로 남겨주세요.
Quiz1 / 4
Q.아래 코드의 실행 결과는 무엇인가요? 왜 그런 결과가 나오는지 Object.freeze()의 동작 방식을 설명하세요.
js
const arr = [1, 2, 3];
Object.freeze(arr);
arr.push(4);

포스트 목록

/study/clab-26-1
파일 13개, 폴더 2개
프론트엔드 스터디 1주차: 마크업 그 이상, 실무를 위한 중급 HTML 가이드프론트엔드 스터디 2주차: 사용자와 소통하는 폼 & CSS의 시작프론트엔드 스터디 3주차: 프론트엔드의 첫 번째 벽, 박스 모델과 스타일링프론트엔드 스터디 4주차: 자유자재 레이아웃 (포지션과 플렉스박스)프론트엔드 스터디 5주차: JavaScript 시작 — 타입, 변수, 그리고 JS가 이상한 이유프론트엔드 스터디 6주차: 객체, 함수, 그리고 스코프프론트엔드 스터디 7주차: 불변성, 프로토타입, 타입 체크프론트엔드 스터디 8주차: 클로저, Promise, async/await프론트엔드 스터디 9주차: React 입문 전 필수 JS 문법 — map, 구조 분해, 스프레드프론트엔드 스터디 10주차: React 기초 1 — 컴포넌트, JSX, props, useState프론트엔드 스터디 11주차: React 기초 2 — useEffect, 이벤트 처리, 폼프론트엔드 스터디 심화: this, 실행 컨텍스트, 이터러블프론트엔드 스터디 심화: 에러 처리와 정규 표현식
;
// original.nested.b 영향 없음
typeof
[
]
===
"object"
&&
[
]
!==
null
)
{
deepFreeze(obj[key]);
}
});
return Object.freeze(obj);
}
Person
(
"영희"
)
;
p1.greet(); // "안녕하세요, 철수입니다."
p2.greet(); // "안녕하세요, 영희입니다."
// p1과 p2의 greet는 같은 함수를 공유
console.log(p1.greet === p2.greet); // true
new
Date
(
)
)
;
// 'Date'
getType(undefined); // 'Undefined'