
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
객체 지향 프로그래밍에서 객체를 생성할 때 초기화를 담당하는 함수 or 메서드
새로운 객체를 생성하는 데 사용
재사용할 수 있는 객체 생성 코드 구현
❗️객체 리터럴 {…}으로도 객체를 만들 수 있지만 유사한 객체를 여러 개 만들 땐? new 연산자 & 생성자 함수 사용하기
✔️속성
키와 값 쌍으로 연결하는 객체 구성원
임의의 자바스크립트 값이 될 수 있다✔️객체
여러 개의 속성을 갖는 데이터 타입
속성 모음을 저장하는 데이터 구조(속성 컬렉션)
k:v
자바스크립트에서의 객체 : 유일한 변경 가능한 값const obj = { a: 1, b() {}, };obj 객체 : 2개의 속성을 가진다
1번째 속성 - 키“a” : 1
2번째 속성 - 메서드“b” : 함수{}
✔️함수 vs 메소드
| 함수(Function) | 메서드(Method) |
|---|---|
| 함수는 특정 작업을 수행하기 위해 설계된 기능 | 메서드는 객체의 프로퍼티가 함수인 경우 |
| 함수는 직접 호출할 수 있다 | 메서드는 점 표기법 or 대괄호 표기법을 사용하여 호출할 수 있다 |
| 재사용 가능하다 | 함수에 비해 재사용하기 어렵다 |
| 함수는 자체적으로 존재한다 | 메서드는 객체와 연결되어 있다 |
✔️new 키워드 : 객체의 구조를 재활용하기 위해 나온 개념
this를 새로운 객체로 설정하고 속성을 초기화한다
함수 자체에 대한 참조란 점에 유의
null 모든 객체에는 constructor 속성이 있다
보통 return문이 없다, 반환해야 할 것들은 모두 this에 저장되고 this는 자동으로 반환되기 때문에 명시적으로 써 줄 필요가 없다
객체를 return 한다면 this 대신 객체가 반환된다
원시형을 return 한다면 return문이 무시된다
function BigUser() {
this.name = "원숭이";
return { name: "고릴라" };
// <-- this가 아닌 새로운 객체를 반환함
}
console.log( new BigUser().name );
// 고릴라
function SmallUser() {
this.name = "원숭이";
return; // <-- this를 반환함
}
console.log( new SmallUser().name );
// 원숭이
function User(name) {
this.name = name;
this.isAdmin = false;
// ↑ this.isAdmin = false; 가 없으면 undefined
// ↑ this.isAdmin = isAdmin; 래퍼런스 에러
}
let user = new User("보라");
// let user = {
// name: "보라",
// isAdmin: false
// };
console.log(user.name); // 보라
console.log(user.isAdmin); // false
- 빈 객체를 만들어
this에 할당한다- 함수 본문을 실행한다.
this에 새로운 프로퍼티를 추가해this를 수정한다this를 반환한다
function User(name) {
// this = {}; (빈 객체가 암시적으로 만들어짐)
// 새로운 프로퍼티를 this에 추가함
this.name = name;
this.isAdmin = false;
// return this; (this가 암시적으로 반환됨)
}
function User(name, isAdmin) {
this.name = name;
this.isAdmin = isAdmin;
}
let user = new User("보라");
// let user = {
// name: "보라",
// isAdmin: undefined
// };
console.log(user.name); // 보라
console.log(user.isAdmin); // undefined
❗️재사용 필요 없는 복잡한 객체 만들 때는?
→ 익명 생성자 함수로 감싸주기
익명 함수이기 때문에 어디에도 저장되지 않고, 애초에 한 번만 호출할 목적이었기에 재사용이 불가능하다let user = new function() { this.name = "John"; this.isAdmin = false; // 사용자 객체를 만들기 위한 여러 코드. // 지역 변수, 복잡한 로직, 구문 등의 // 다양한 코드가 여기에 들어갑니다. };
[new.target] 프로퍼티를 사용하면 함수가 new와 함께 호출되었는지 아닌지 확인할 수 있다
✔️프로퍼티 : 데이터 구조와 연관된 속성
필드, 메소드 기능 중간 연결
key : value 형식으로 구성
function User() {
alert(new.target);
}
// 'new' 없이 호출함
User(); // undefined
// 'new'를 붙여 호출함
new User(); // function User { ... }
부모 객체, 모든 객체들이 메소드, 속성들을 상속 받기 위한 객체
✔️프로토, 프로토타입
프로토 : 처음
프로토타입 : 실험용으로 만들어본 것
자바스크립트는 프로토타입 기반 언어이다
= 모든 자바스크립트 함수는 프로토타입 속성을 가진다
생성자 함수로 생성된 객체들은 해당 프로토타입 상속 받는다
프로토타입에 정의된 속성, 메서드는 생성된 모든 객체에 공유된다
✔️클래스, 인스턴스 객체
클래스 : 객체를 생성하기 위한 설계도
실제로 메모리 상에 할당되지 않는다
인스턴스 : 클래스로부터 생성된 구체적 객체
클래스 객체가 메모리에 할당되어 실제로 존재하는 상태
⭐️클래스 기반 언어 vs 프로토타입 기반 언어
- 클래스 기반 언어에서는 상속
- 프로토타입 기반 언어에서는 어떤 객체를 원형으로 삼고 이를 복제함으로써 상속과 비슷한 효과를 낸다
클래스, 인스터스 개념 없이 객체 생성 방법만 존재
대부분 프로그래밍은 클래스 기반 언어이다
❓그럼 왜 자바스크립트 프로토타입 기반 언어를 선택?
1. 쉬운 언어가 필요해서
브라우저 전쟁에서 등장한 자바스크립트
개발에 대한 지식이 깊지 않은 사람들도 사용할 수 있는 간단한 언어가 필요했다const person = { name: 'bling', gender: 'male' }public class app { public static void main(String[] args) { final Person person = new Person("bling", "male"); } public static class Person { private final String name; private final String gender; public Person(final String name, final String gender) { this.name = name; this.gender = gender; } } }
↑ 객체 생성만 봐도 클래스 기반 언어, 자바 보다 자바스크립트가 더 간편하다
그리고 이렇게 간편하게 만들 수 있는 이유엔 내장 클래스 Object.prototype 속성이 숨겨져 있기 때문
- 상속 vs 복사, 위임
상속 : 안정적, 예측 가능하지만 결합성이 높기 때문에 유동적이지 않다
복사, 위임 : 참조하는 방식이기에 결합성이 낮아서 유동적이다. 그래서 내부는 복잡하지만, 사용할 때 만큼은 간단하게 사용할 수 있는 것
❗️결국 자바스크립트가 프로토 기반 언어를 선택한 것은 쉬운 언어가 필요했기 때문에 기존의 클래스 기반 언어 방식과 다르게 만들었다
❓그럼 자바스크립트엔 클래스가 없나?
NO. ES6 이후부터 클래스 등장 (문법적 설탕, syntactic sugar)
기존 언어에 익숙한 개발자들이 자바스크립트 사용할 때 어려움이 있어서 도입
특정 생성자 함수 또는 객체가 상속할 속성과 메서드를 저장하는 객체이다
= 자신을 원형으로 다른 객체가 참조
constructor : 프로토타입 객체와 같이 생성되었던 함수
__proto__ : 프로토타입 링크

프로토타입 체인에 따라 속성, 메서드를 검색한다
상위에서 물려받은 객체 정보를 담은 것
객체에서 특정 속성이나 메서드를 찾을 때, 해당 객체에 없으면 __proto__를 따라 상위 프로토타입 객체를 탐색하는 구조이다
✔️프로토타입 객체 vs 프로토타입 체인
- 프로토타입 객체 : 특정 생성자 함수에서 생성된 모든 객체가 공유하는 속성, 메서드를 정의하는 객체
- 프로토타입 체인 : 객체에서 속성 검색할 때, 현재 객체에서 찾을 수 없는 부모 객체(프로토타입 객체)를 따라가는 구조
모든 프로토타입 객체에는 constructor 속성이 있고 원래 생성자 함수를 가리킨다
console.log(Person.prototype.constructor === Person);
// true
console.log(person1.constructor === Person);
// true
// 만약 prototype을 완전히 변경하면 constructor가 끊어질 수 있다
Person.prototype = {
sayHi: function() {
console.log("Hi!");
}
};
console.log(person1.constructor === Person);
// false (끊어짐)
// 이런 경우 constructor를 다시 연결해 줄 수 있습니다.
Person.prototype.constructor = Person;
ES6 이후에는 class 문법이 등장하면서 prototype 기반의 객체 지향 프로그래밍을 더 쉽게 사용할 수 있다
하지만 내부적으로 class도 prototype을 활용하여 동작한다
✔️
__proto__(던더프로토) :[[Prototype]]용 getter·setter
이 방법은 오래된 방법이라 ↓ 방법을 좀 더 권장한다
- Object.create(proto, [descriptors]) –
[[Prototype]]이proto를 참조하는 빈 객체를 만든다
이때 프로퍼티 설명자를 추가로 넘길 수 있다- Object.getPrototypeOf(obj) –
obj의[[Prototype]]을 반환한다- Object.setPrototypeOf(obj, proto) –
obj의[[Prototype]]이proto가 되도록 설정한다
✔️[[Prototype]] 역사
아주 오래전부터 사용되었다
2012년부터 Object.create 가 추가되었지만 객체 생성만 가능하고 프로토타입 얻거나 설정하는 것은 불가능했다
→__proto__구현해서 프로토타입 얻고 설정하게 했다
BUT
2015년부터Object.setPrototypeOf,Object.getPrototypeOf등장
하지만, 여전히 __proto__ 많이 쓰여서 이게 표준이 되어버린 것
결론 : 모두 다 사용 가능하다
❗️그럼
Object.setPrototypeOf,Object.getPrototypeOfvs proto
객체 생성할 때만 [[Prototype]] 설정하고 수정하지 않기에
✔️[null-prototype 객체]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects
✔️심볼(symbol)
객체 고유 식별자를 만들 때 사용된다
변경이 불가능한 원시값이다
new연산자를 이용한 래퍼 객체 생성이 불가능하다
✔️new 연산자, 생성자 함수
객체 여러 개를 쉽게 만들 수 있다
1. 함수 이름 첫 글자는 대문자로 시작
2. 반드시 new 연산자 붙여 실행한다
❗️모든 함수는 생성자 함수가 될 수 있다
new 연산자를 붙이면 어떤 함수라도 알고리즘 실행 가능
✔️래퍼 객체
자바스크립트 내장 객체
원시 값을 감싸 객체처럼 메서드, 프로퍼티 사용할 수 있도록 해준다
끝나면, 임시 객체는 소멸하고 실제 원시 타입 값에는 영향 주지 않는다
생성자 함수(constructor function)는 객체를 생성하는 함수이다
첫글자 대문자 사용, new 키워드로 호출한다
prototype 객체를 활용하면 여러 객체가 같은 메서드를 공유할 수 있다
prototype 체인을 통해 상속이 이루어진다
constructor 속성은 생성자를 가리키며, prototype을 변경할 때 유의해야 한다
ES6의 class 문법도 내부적으로 prototype을 기반으로 동작한다