본문 바로가기
language/javascript

🧩 this, new, instanceof, constructor – 자바스크립트 객체 생성과 관계 완전 이해

by 죄니안죄니 2025. 5. 9.

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를 붙이면 아래와 같은 일이 발생합니다:

  1. 빈 객체가 만들어짐
  2. this가 그 객체로 바인딩됨
  3. 함수가 실행됨
  4. 명시적 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()를 활용해 프로토타입 기반 상속을 어떻게 구현할 수 있는지 실전 중심으로 정리하겠습니다.

댓글