this, new, instanceof, constructor – 자바스크립트 객체 생성과 관계 완전 이해
자바스크립트에서 객체와 함수는 긴밀히 연결되어 있으며, this
, new
, instanceof
, constructor
는 모두 객체 생성 및 메서드 호출 시 핵심 개념입니다.
이번 글에서는 이 네 가지 키워드의 역할과 관계를 개념 + 코드 예제 중심으로 완벽히 정리합니다.
1. this – 호출 컨텍스트에 따라 달라지는 값
this
는 선언 시점이 아닌 호출 시점에 따라 결정됩니다.
📌 전역 또는 일반 함수 호출
function showThis() {
console.log(this);
}
showThis(); // 👉 브라우저에선 window, strict 모드에선 undefined
📌 객체의 메서드로 호출
const user = {
name: "Alice",
sayHi() {
console.log(this.name);
}
};
user.sayHi(); // 👉 "Alice"
📌 화살표 함수는 this를 바인딩하지 않음
const obj = {
name: "Bob",
arrowFn: () => {
console.log(this.name); // ❌ 전역 this (undefined)
}
};
obj.arrowFn();
✅ 실무 팁: 화살표 함수 내부의 this
는 외부 스코프의 this
를 그대로 사용합니다.
2. new – 생성자 함수를 통한 객체 생성
📌 생성자 함수
function Person(name) {
this.name = name;
}
const p1 = new Person("Alice");
console.log(p1.name); // 👉 "Alice"
new
를 붙이면 아래와 같은 일이 발생합니다:
- 빈 객체가 만들어짐
this
가 그 객체로 바인딩됨- 함수가 실행됨
- 명시적 return 없으면
this
가 반환됨
📌 명시적으로 객체를 리턴하면?
function User() {
this.role = "admin";
return { role: "guest" };
}
const u = new User();
console.log(u.role); // 👉 "guest" (명시적 객체 리턴됨)
3. instanceof – 어떤 생성자로부터 만들어졌는지 확인
function Animal() {}
const dog = new Animal();
console.log(dog instanceof Animal); // 👉 true
//Animal.prototype 이 dog의 프로토타입 체인 어딘가에 있는가?
//dog.__proto__, dog.__proto__.__proto__, ... 에 Animal.prototype이 존재하면 true를 반환합니다.
console.log(dog instanceof Object); // 👉 true (모든 객체는 Object 상속)
instanceof
는 내부적으로 __proto__
와 prototype
체인을 따라가며 확인합니다.
4. constructor – 객체를 생성한 함수 참조
function Car() {}
const myCar = new Car();
console.log(myCar.constructor === Car); // 👉 true
모든 객체는 기본적으로 생성자를 가리키는 constructor
속성을 갖습니다.
constructor 속성은 단순한 속성일 뿐입니다.
📌 직접 constructor를 바꿀 수도 있음 (주의)
const custom = {
name: "Custom"
};
custom.constructor = String;
console.log(custom instanceof String); // 👉 false
console.log(Object.getPrototypeOf(custom)); // 👉 Object.prototype
✅ Object.getPrototypeOf(obj)는 해당 객체의 [[Prototype]], 즉 상속받은 바로 윗 객체를 반환합니다. 대체로는 생성자의 .prototype이 맞지만, 항상 그런 건 아닙니다.
constructor 속성을 바꾼다고 해서 instanceof 판단 기준이 바뀌지는 않습니다.
이건 그냥 custom 객체에 "constructor"라는 키로 String 함수를 저장한 것일 뿐, 실제 프로토타입 체인에는 아무런 영향도 주지 않아요.
즉, custom의 prototype chain은 여전히:
custom
↑
Object.prototype
↑
null
이고, String.prototype은 그 체인에 존재하지 않습니다. 이 체인 어딜 봐도 String.prototype은 없습니다.
✅ 반대로 new String()을 쓰면?
const strObj = new String("hello");
console.log(Object.getPrototypeOf(strObj)); // 👉 String.prototype
console.log(strObj instanceof String); // 👉 true
→ 이 경우는 진짜로 String.prototype이 prototype chain 안에 포함되어 있기 때문에 instanceof String === true가 되는 것입니다.
🔎 Object.getPrototypeOf(obj)
// 🔎 1. new 생성자()로 만든 경우
function Person() {}
const p = new Person();
console.log(Object.getPrototypeOf(p) === Person.prototype); // 👉 true
// → ✅ new 키워드로 객체를 생성하면,
// 그 객체의 prototype chain 첫 번째는 바로 생성자.prototype입니다.
//-------------------------------------------------------
// 🔎 2. 리터럴로 만든 경우
// 객체 리터럴
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype); // 👉 true
// 배열 리터럴
const arr = [];
console.log(Object.getPrototypeOf(arr) === Array.prototype); // 👉 true
// 함수 리터럴
function fn() {}
console.log(Object.getPrototypeOf(fn) === Function.prototype); // 👉 true
//문자열 객체
const str = new String("abc");
console.log(Object.getPrototypeOf(str) === String.prototype); // 👉 true
//-------------------------------------------------------
// 🔍 반례: Object.create를 쓰는 경우
const proto = { greeting: "hello" };
const obj = Object.create(proto);
console.log(Object.getPrototypeOf(obj) === proto); // 👉 true
// → 이 경우엔 .prototype이 아닌 직접 명시한 객체가 prototype으로 설정됨
Object.create()는 자바스크립트에서 객체의 프로토타입을 명시적으로 설정할 수 있는 방법.
객체를 만들면서 그 프로토타입을 직접 설정할 수 있는 유일한 표준 방식
🔍 기본 문법
Object.create(proto, propertiesObject?)
- proto: 새 객체의 프로토타입으로 설정할 객체 (null도 가능)
- propertiesObject: 선택. Object.defineProperties와 같은 방식으로 속성 정의 가능
✅ 예제: 직접 프로토타입 지정
const proto = {
sayHi() {
console.log("Hi!");
}
};
const obj = Object.create(proto);
obj.name = "Custom";
console.log(obj.name); // 👉 "Custom"
obj.sayHi(); // 👉 "Hi!"
console.log(Object.getPrototypeOf(obj) === proto); // 👉 true
// new 와 비교
function Person() {}
const p1 = new Person();
const proto = { greet: () => console.log("Hello") };
const p2 = Object.create(proto);
console.log(Object.getPrototypeOf(p1) === Person.prototype); // 👉 true
console.log(Object.getPrototypeOf(p2) === proto); // 👉 true
🧠 여기서 obj는 proto를 직접 상속했기 때문에 obj.sayHi()가 작동합니다.
✅ 빈 객체를 만들고 싶을 때 ✅ Object.create(proto, propertiesObject) 형태
const empty = Object.create(null);
console.log(Object.getPrototypeOf(empty)); // 👉 null
console.log(typeof empty.toString); // 👉 undefined
dict["apple"] = "사과";
dict["toString"] = "문자열 변환"; // 충돌 없음
console.log(dict["toString"]); // 👉 "문자열 변환"
➡️ Object.prototype조차 상속하지 않아서 완전히 깨끗한 "딕셔너리 용도"로 자주 사용됩니다.
💡 실무 활용 팁
목적 | Object.create()가 유리한 경우 |
💾 순수 딕셔너리 만들기 | Object.create(null) |
🔁 유연한 프로토타입 체인 구성 | 동적으로 proto 전달 |
🧪 테스트/Mock 객체 만들기 | 최소 구조만 가진 객체 생성 |
* 딕셔너리 : “키(key)”로 값을 빠르게 찾기 위한 객체 구조
언어 | 용어 |
Python | dict |
Java | HashMap |
C++ | map, unordered_map |
JavaScript | {} 객체 또는 Map 객체 |
✅ Object.create(proto, propertiesObject) 형태
const proto = {
greet() {
console.log("Hello");
}
};
const obj = Object.create(proto, {
name: {
value: "Alice",
writable: false, // 읽기 전용
enumerable: true,
configurable: true
},
age: {
value: 30,
writable: true,
enumerable: true
}
});
console.log(obj.name); // 👉 "Alice"
obj.name = "Bob";
console.log(obj.name); // 👉 여전히 "Alice" (writable: false 때문)
✅ 특징:
- 두 번째 인자인 propertiesObject는 Object.defineProperties()와 완전히 동일한 구조입니다.
- 즉, 초기 생성과 동시에 세부 속성 제어를 할 수 있다는 것이 장점입니다.
⚙️ 실무에서는 언제 쓰일까?
사용 상황 | 왜 이 방식이 유용한가 |
💾 읽기 전용 속성 정의 | writable: false, getter만 정의 |
🛠 상속 + 설정 동시 필요 | prototype 체인 + 속성 선언 결합 |
🧪 정확한 제어 필요할 때 | defineProperty를 별도로 호출하지 않아도 됨 |
✋ 그런데 일반적인 상황에서는?
실제로는 아래처럼 2단계로 분리해서 쓰는 경우가 훨씬 더 많습니다:
const obj = Object.create(proto);
obj.name = "Alice"; // 간단
// 또는 필요하면 별도로 제어
Object.defineProperty(obj, "name", {
value: "Alice",
writable: false
});
✅ 가독성과 직관성이 높고, 코드가 짧아지기 때문이에요.
✅ 결론
질문 | 답변 |
Object.create(proto, propertiesObject) 자주 쓰이나요? | ❌ 자주 쓰이지는 않지만 |
언제 쓰나요? | ✅ 속성 제어 + 상속을 동시에 하려는 경우 |
실무에서는? | ✅ 보통은 Object.create(proto) + obj.key = val로 충분 |
5. 네 개의 관계 요약
키워드 | 설명 | 중요 포인트 |
---|---|---|
this |
함수 실행 시 컨텍스트 결정 | 호출 방식에 따라 달라짐 |
new |
생성자 함수로 객체 생성 | this를 새 객체에 바인딩 |
instanceof |
객체가 어떤 생성자로 만들어졌는지 확인 | prototype 체인 확인 |
constructor |
객체의 생성자 함수 정보 | 변조 가능성 있음 (주의) |
📌 마무리
this
, new
, instanceof
, constructor
는 객체 중심 언어인 자바스크립트의 핵심 동작 원리를 이해하는 데 반드시 필요한 요소입니다.
이들의 관계를 명확히 이해하면 함수 호출의 컨텍스트나 객체 생성 흐름을 더 유연하게 다룰 수 있습니다.
다음 글에서는 Object.create()
를 활용해 프로토타입 기반 상속을 어떻게 구현할 수 있는지 실전 중심으로 정리하겠습니다.
'language > javascript' 카테고리의 다른 글
🧩 배열(Array) vs 유사 배열 객체(Array-like) – 차이와 활용법 완전 정리 (0) | 2025.05.10 |
---|---|
🧩 Object.create로 프로토타입 기반 상속 구현하기 (0) | 2025.05.10 |
🧩 Object 유틸 함수 실전 예제: assign, keys, entries, fromEntries 완전 정복 (0) | 2025.05.09 |
🧩 자바스크립트 객체(Object) 선언, 접근, 삭제, 열거 – 실무 패턴 정리 (0) | 2025.05.09 |
🧩 자바스크립트의 기본 자료형(Primitive) vs 참조형(Object) 완전 정리 (0) | 2025.05.09 |
댓글