딥다이브 요약 GitHub
안녕하세요. 7주차입니다. 이번 주는 다른 언어 경험자에게 JS가 가장 낯설게
느껴지는 구간입니다. 프로토타입은 Java나 Python의 클래스
상속과 근본적으로 다른 JS만의 상속 방식이고, 불변성은
const를 써도 왜 완전히 불변이 아닌지를 이해하는 개념입니다. 타입 체크는 동적
타입 언어에서 런타임 안전성을 확보하는 방법입니다.
아래 10문제를 막힘없이 풀 수 있다면,
이번 주 학습 자료를 생략하거나, 모르는 부분만 선택적으로 읽으셔도 좋습니다.
바로 하단의 더 알면 좋을 것들을 확인해보세요.
많은 분들이 const를 쓰면 값이 변하지 않는다고 오해합니다.
하지만 const는 변수가 가리키는 참조(주소)를 고정할 뿐, 그
주소에 있는 객체 내부 변경은 막지 않습니다.
const obj = { x: 1 };
obj.x = 99; // 가능 — 내부 프로퍼티 변경
obj.y = 100; // 가능 — 프로퍼티 추가
delete obj.x; // 가능 — 프로퍼티 삭제
obj = {}; // TypeError — 재할당만 불가
객체를 복사할 때도 주의가 필요합니다. spread(...)나 Object.assign()은
얕은 복사 (shallow copy)로, 1단계 깊이만 새로운 값으로
복사됩니다. 중첩 객체는 여전히 참조를 공유합니다.
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
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)가 이 방식을 따릅니다.
Java나 Python은 클래스 기반 상속입니다. 클래스를 정의하고
extends로 상속합니다. JS는 다릅니다. 프로토타입 기반 상속
으로, 객체가 다른 객체를 직접 상속합니다. ES6의 class 문법도 내부적으로는
프로토타입을 사용합니다.
모든 JS 객체는 [[Prototype]]이라는 내부 슬롯을 가지며, 이 슬롯이 상위
프로토타입 객체를 가리킵니다. 프로퍼티를 참조할 때 자신에게 없으면
프로토타입 체인을 따라 상위로 탐색합니다.
const obj = { x: 1 };
// obj에는 toString이 없지만 사용 가능
console.log(obj.toString()); // "[object Object]"
// 프로토타입 체인: obj → Object.prototype → null
// toString은 Object.prototype에 있음
function Person(name) {
this.name = name;
// 여기에 메서드를 넣으면 인스턴스마다 함수가 복사됨 — 비효율
}
// prototype에 메서드를 추가하면 모든 인스턴스가 공유
Person.prototype.greet = function () {
console.log(`안녕하세요, ${this.name}입니다.`);
};
const p1 = new Person("철수");
const p2 = new
[[Prototype]]: 모든 객체가 가지는 내부 슬롯. 상위
프로토타입을 가리킴. __proto__로 접근 가능 (권장 안 함)prototype: 함수 객체만 가지는 프로퍼티. new로 인스턴스를
만들 때 인스턴스의 [[Prototype]]이 됨function Foo() {}
const foo = new Foo();
console.log(foo.__proto__ === Foo.prototype); // true
console.log(Foo.prototype.constructor === Foo); // true
"hello".toUpperCase(); // "HELLO"
(42).toFixed(2); // "42.00"
// 원시값은 객체가 아닌데 어떻게 메서드가 있을까?
// JS 엔진이 메서드 호출 시 임시로 래퍼 객체(String, Number)로 변환
// 메서드 실행 후 래퍼 객체는 즉시 제거됨
정적 타입 언어(Java, TypeScript)에서는 컴파일 타임에 타입 오류를 잡아줍니다. 순수 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()
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(
// 배열 확인 — 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가 사실상 표준인 이유 중 하나입니다.
아래 코드를 브라우저 콘솔에서 직접 실행해보고 결과를 입력해보세요.
const obj = Object.freeze({ x: 1, nested: { y: 2 } });
obj.x = 99;
obj.nested.y = 99;
console.log(obj.x, obj.nested.y);const arr = [1, 2, 3];
Object.freeze(arr);
arr.push(4);