개요
함수는 객체다
근데 객체는 함수 아님
17.1 Object 생성자 함수
new Object() 로 빈 객체를 생성하고 프로퍼티를 동적으로 추가하는 방식. 빌트인 생성자 함수(String, Number, Boolean, Function, Array, Date, RegExp, Promise 등)도 생성이 가능하다.
자바에서는 너무나도 친숙한 이 방법이 객체 리터럴이라는 방식에 먹혀 사용되지 않는다고 한다... 이럴수가
17.2 생성자 함수
17.2.1 객체 리터럴에 의한 객체 생성 방식의 문제점
이놈도 문제가 있긴 있음
그것은 바로 반복해서 객체를 생성해야할때 매번 추가해줘야하는것
const person1 = {
name: "Kim",
age: 20,
introduce() {
console.log(`안녕하세요. 저는 ${this.name}입니다.`);
}
};
const person2 = {
name: "Lee",
age: 25,
introduce() {
console.log(`안녕하세요. 저는 ${this.name}입니다.`);
}
};
정말 귀찮군 ㅋㅋ
17.2.2 생성자 함수에 의한 객체 생성 방식의 장점
생성자 함수와 함께라면 이런 반복을 피할 수 있긴 함
function Test(name) {
this.name = name;
introduce() {
console.log(`안녕하세요. 저는 ${this.name}입니다.`);
}
};
const name1 = new Test('Jeon');
const name2 = new Test('Kim');
name1.introduce();
name2.introduce(); // 너무나도 익숙한 이 패턴...
근데 이 this가 문제임.. 일반 함수에서 호출하면 전역 객체를 가르키고, 메서드로서 호출하면 메서드를 호출한 객체.
마지막으로 생성자 함수에서 호출하면 생성자 함수가 미래에 생성할 인스턴스에 할당된다고 한다...
추가로 new 연산자와 함께 생성해야 인스턴스가 생기고 그렇지 않으면 일반 함수로 동작한다고 함 ㅋㅋ
즉 new 연산자의 유무가 해당 함수를 생성자 함수로 동작할 것 인지, 일반 함수로 동작할 것 인지 판단한다고 함
17.2.3 생성자 함수의 인스턴스 생성 과정
생성자 함수는 인스턴스를 생성, 초기화 하는 역할을 가지고 있음
function Person(name) {
this.name = name;
}
new Person("Jeon"); // 생성자 함수로 호출
암묵적으로 빈 객체가 생성, 그리고 그 인스턴스는 this에 바인딩된다.
빈 객체를 생성하고 this를 를 할당해주는게 뭔가 호이스팅같지만 조금 다르다고 함
// 1. 빈 객체 생성
const thisObj = {};
// 2. this 바인딩
// this === thisObj
인스턴스를 초기화 해줌
생성자 함수에 기술되어 있는 코드가 한 줄씩 실행되며 this에 바인딩되어있는 인스턴스를 초기화한다고 함
// 3. 함수 본문 실행
thisObj.name = "Jeon";
그 뒤 암묵적으로 this를 반환함.
// 4. 완성된 객체 반환
return thisObj;
즉 빈 객체를 생성 > 빈 객체를 this에 바인딩 > 인스턴스(this)를 초기화 > 바인딩된 객체를 반환 하는 순서로 진행되는것
호이스팅과 다른점이라 하면 해당 생성자 함수 호출 시점에 모든게 만들어지기 때문에 자스 초기화 단계에서 undefined를 할당해주는 호이스팅과는 다른것
골떄리는건 암묵적으로 this를 반환해주는 동작을 하기 때문에 명시적으로 반환값이 있으면 그게 우선순위를 갖는다고 함 ㅋㅋ
또 골때리는건 원시값을 반환하면 무시됨 ㅋㅋ
function Person(name) {
this.name = name;
return 100;
}
const result = new Person("Jeon");
console.log(result); // Person { name: 'Jeon' }
근데 또 객체를 반환하면 객체가 우선시된다
function Person(name) {
this.name = name;
return {
name: "Kim"
};
}
const result = new Person("Jeon");
console.log(result); // { name: 'Kim' }
원시값은 왜 무시되는걸까...?
생성자 함수는 객체를 만들기 위한 함수이므로
원시값 반환은 의미가 없어서 무시하고 this를 반환한다.
객체 반환은 개발자의 명시적 의도로 간주하여 그 객체를 반환한다. 아오 ㅋㅋ
17.2.4 내부 메서드 Call과 Construct
Call, Construct ㅋㅋ
Python에선 너무너무나도 익숙한 이 방식이 아자스에도 있다니 괜히 반갑군 ㅋㅋ
일반 객체는 호출이 불가능하다 하지만 함수는 호출이 가능함.
왜일까???????????????????????????
함수 객체만을 위한 [Environment], [FormalParameters] 등의 내부 슬롯과
[Call], [Construct] 같은 내부 메서드를 추가로 가지고 있음
함수가 호출될땐 저 Call 메서드를 호출하는것임 ㅋㅋ
function hello(name) {
return `Hello ${name}`;
}
console.log(hello("Jeon")); // hello.[[Call]]("Jeon"); 과 같음
추가로 new와 함께 호출되면 Construct가 호출되는것임
function Person(name) {
this.name = name;
}
const person = new Person("Jeon");
// 내부적으로는
// Person.[[Construct]]("Jeon")
즉 [[Construct]]는 위에서 설명했던 빈 객체 생성 + this 바인딩 + 초기화 + 반환 과정 전체를 수행하는 내부 메서드 인 것이다
함수는 모두 Callable이면서 생성자를 가지고 있을수도, 없을수도 있다는것
거참 복잡시럽게
17.2.5 constructor와 non-constructor의 구분
복잡시럽게 구분이 가능함
function foo() {};
const bar = function () {};
const baz = {
x: function() {}
}
// 셋 다 constructor를 지니고 있음
new foo();
new bar();
new baz.x();
// 화살표 함수는 Call만 가지고 있음
const arrow = () => {};
new arrow(); // TypeError
// 메서드 축약 표현은 같은 객체의 동작을 표현하려고 만든 문법이라 신규 객체를 생성하지 않는다고 함
const obj = {
x() {}
}
new obj.x(); // TypeError
17.2.6 new 연산자
new와 함께 호출하면 Construct 호출 → 인스턴스 생성. new 없이 호출하면 일반 함수로 동작하는 위험이 있다
function add(x, y) {
return x + y;
}
let inst = new add();
console.log(inst); // 원시값 반환을 무시하는 생성자 함수의 특성때문에 빈 객체가 return된다
Call은 단순 실행이라 x, y값을 반환하지만 Construct는 생성자 함수라서 this에 스스로를 바인딩한 뒤 내부동작을 수행하고 스스로를 반환한다.
이때 원시값은 무시해버림 ㅋㅋ
추가로 this로 바인딩 한 함수를 일반 함수로 호출해버린다...?
function Circle(radius) {
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
};
}
const circle = Circle(5);
console.log(circle); // undefined
console.log(radius); // 5
console.log(getDiametar()); // 10
circle.getDiameter(); // TypeError 레전드 ㅋㅋ
17.2.7 new.target
이 난리를 막기 위해 target이 있다.
생성자 함수가 new 없이 호출되는 것을 방지 — new.target으로 호출 방식 확인. 스코프 세이프 생성자 패턴을 제공한다
function Person(name) {
if (!new.target) {
throw new Error("new 연산자와 함께 호출해야 합니다.");
}
this.name = name;
}
const person = new Person("Jeon");
console.log(person.name); // Jeon
Person("Kim"); // Error: new 연산자와 함께 호출해야 합니다.
이런식으로 사전에 잡아내는것도 가능하고, 반대로 무조건 생성자 함수로 호출하도록 재귀 적으로 코드를 작성할수도 있다
function Person(name) {
if (!new.target) {
return new Person(name);
}
this.name = name;
}
const person1 = Person("Jeon"); // new 없이 호출
const person2 = new Person("Kim"); // new와 함께 호출
console.log(person1); // Person { name: 'Jeon' }
console.log(person2); // Person { name: 'Kim' }
환장해부리것서 ㅋㅋ
참고 자료
'코딩딩 > Javascript' 카테고리의 다른 글
| 날것 - let, const 키워드와 블록 레벨 스코프 (0) | 2026.05.26 |
|---|---|
| 날것 - 전역 변수의 문제점 (0) | 2026.05.19 |
| 날것 - 스코프 (0) | 2026.05.19 |
| 날것 - 함수 (0) | 2026.05.12 |
| 날것 - 원시 값과 객체의 비교 (1) | 2026.04.15 |