프로토타입(constructor함수, 프로토타입 객체)

oYJo·2025년 4월 3일

JavaScript

목록 보기
51/52

프로토타입

1️⃣ constructor 함수

생성자 함수(constructor function)

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 대괄호 표기법을 사용하여 호출할 수 있다
재사용 가능하다함수에 비해 재사용하기 어렵다
함수는 자체적으로 존재한다메서드는 객체와 연결되어 있다

사용조건

  1. 함수 이름 첫 글자 대문자로 시작
  2. 반드시 new 연산자 붙여 실행

✔️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 );  
      // 원숭이

예시1

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
  1. 빈 객체를 만들어 this에 할당한다
  2. 함수 본문을 실행한다. this에 새로운 프로퍼티를 추가해 this를 수정한다
  3. this를 반환한다
function User(name) {
  // this = {};  (빈 객체가 암시적으로 만들어짐)

  // 새로운 프로퍼티를 this에 추가함
  this.name = name;
  this.isAdmin = false;

  // return this;  (this가 암시적으로 반환됨)
}

예시2

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

2️⃣ new function() {…}

❗️재사용 필요 없는 복잡한 객체 만들 때는?
→ 익명 생성자 함수로 감싸주기

익명 함수이기 때문에 어디에도 저장되지 않고, 애초에 한 번만 호출할 목적이었기에 재사용이 불가능하다

let user = new function() {
  this.name = "John";
  this.isAdmin = false;
  // 사용자 객체를 만들기 위한 여러 코드.
  // 지역 변수, 복잡한 로직, 구문 등의
  // 다양한 코드가 여기에 들어갑니다.
};

3️⃣ new.target, 생성자함수

[new.target] 프로퍼티를 사용하면 함수가 new와 함께 호출되었는지 아닌지 확인할 수 있다

✔️프로퍼티 : 데이터 구조와 연관된 속성
필드, 메소드 기능 중간 연결
key : value 형식으로 구성

function User() {
  alert(new.target);
}
// 'new' 없이 호출함
User(); // undefined
// 'new'를 붙여 호출함
new User(); // function User { ... }

4️⃣ prototype 객체

부모 객체, 모든 객체들이 메소드, 속성들을 상속 받기 위한 객체

✔️프로토, 프로토타입

프로토 : 처음

프로토타입 : 실험용으로 만들어본 것

  • 자바스크립트는 프로토타입 기반 언어이다
    = 모든 자바스크립트 함수는 프로토타입 속성을 가진다

  • 생성자 함수로 생성된 객체들은 해당 프로토타입 상속 받는다

  • 프로토타입에 정의된 속성, 메서드는 생성된 모든 객체에 공유된다

✔️클래스, 인스턴스 객체

클래스 : 객체를 생성하기 위한 설계도
실제로 메모리 상에 할당되지 않는다

인스턴스 : 클래스로부터 생성된 구체적 객체
클래스 객체가 메모리에 할당되어 실제로 존재하는 상태

⭐️클래스 기반 언어 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 속성이 숨겨져 있기 때문
  1. 상속 vs 복사, 위임

    상속 : 안정적, 예측 가능하지만 결합성이 높기 때문에 유동적이지 않다

    복사, 위임 : 참조하는 방식이기에 결합성이 낮아서 유동적이다. 그래서 내부는 복잡하지만, 사용할 때 만큼은 간단하게 사용할 수 있는 것

❗️결국 자바스크립트가 프로토 기반 언어를 선택한 것은 쉬운 언어가 필요했기 때문에 기존의 클래스 기반 언어 방식과 다르게 만들었다

❓그럼 자바스크립트엔 클래스가 없나?
NO. ES6 이후부터 클래스 등장 (문법적 설탕, syntactic sugar)

기존 언어에 익숙한 개발자들이 자바스크립트 사용할 때 어려움이 있어서 도입


5️⃣ 프로토타입 객체

특정 생성자 함수 또는 객체가 상속할 속성과 메서드를 저장하는 객체이다

= 자신을 원형으로 다른 객체가 참조

  • 모든 함수(생성자 함수 포함)는 기본적으로 prototype 속성을 가진다
  • 생성자 함수를 통해 생성된 모든 객체는 해당 생성자의 prototype 객체를 공유한다
  • 프로토타입 객체에 추가된 속성과 메서드는 해당 프로토타입을 상속받은 모든 객체에서 사용할 수 있다

기본적인 속성

constructor : 프로토타입 객체와 같이 생성되었던 함수
__proto__ : 프로토타입 링크

목적

  • 메모리 절약 : 같은 메서드를 개별 객체에 복사하지 않고, 공유할 수 있다
  • 객체 간 상속을 구현하는 기반이 된다

6️⃣ 프로토타입 체인(Prototype chain), 프로토타입 링크

프로토타입 체인에 따라 속성, 메서드를 검색한다

상위에서 물려받은 객체 정보를 담은 것

객체에서 특정 속성이나 메서드를 찾을 때, 해당 객체에 없으면 __proto__를 따라 상위 프로토타입 객체를 탐색하는 구조이다

객체에서 속성 찾을 때

  1. 객체 자체에서 찾는다
  2. 없으면 prototype 객체에서 찾는다
  3. 계속해서 Object.prototype까지 탐색한다
  4. 여기서도 없으면 undefined를 반환하다

목적

  • 코드 재사용 : 상위 객체의 속성과 메서드를 하위 객체에서도 사용할 수 있도록 한다
  • 객체 간 계층 구조를 형성하여 상속 기능을 제공한다

✔️프로토타입 객체 vs 프로토타입 체인

- 프로토타입 객체 : 특정 생성자 함수에서 생성된 모든 객체가 공유하는 속성, 메서드를 정의하는 객체

- 프로토타입 체인 : 객체에서 속성 검색할 때, 현재 객체에서 찾을 수 없는 부모 객체(프로토타입 객체)를 따라가는 구조

❓constructor 속성과 프로토타입 연관성

모든 프로토타입 객체에는 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
이 방법은 오래된 방법이라 ↓ 방법을 좀 더 권장한다

✔️[[Prototype]] 역사
아주 오래전부터 사용되었다
2012년부터 Object.create 가 추가되었지만 객체 생성만 가능하고 프로토타입 얻거나 설정하는 것은 불가능했다
__proto__ 구현해서 프로토타입 얻고 설정하게 했다
BUT
2015년부터 Object.setPrototypeOf, Object.getPrototypeOf 등장

하지만, 여전히 __proto__ 많이 쓰여서 이게 표준이 되어버린 것
결론 : 모두 다 사용 가능하다

  • 추가로, 속도가 중요하다면 변경하는 것을 권장하지 않는다

❗️그럼 Object.setPrototypeOf, Object.getPrototypeOf vs 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을 기반으로 동작한다

profile
Hello! My Name is oYJo

0개의 댓글