TIL archiving ···.ᐟ/JavaScript + TypeScript

[노트내용정리] 생성자 함수 & Class (feat. 프로토타입, instance, new)

dayoung-archive 2024. 9. 16. 19:41

📌 생성자 함수 (constructor function)

  • 객체를 생성하기 위한 함수
  • 유사한 객체 여러 개를 쉽게 만들 수 있다.
  • 일반함수와 구분하기 위해 'new' 연산자를 사용해 호출하고, 첫 번째 문자를 대문자(파스칼 케이스)로 작성한다.
new 연산자
- 빈 객체를 생성한다.
- 새로 생성된 빈 객체는 생성자의 프로토타입을 상속받는다.
- this를 새로 생성된 객체에 바인드 시킨다.
- 생성자에 명시적으로 다른 객체를 리턴하지 않는 경우, this로 바인드된 객체가 반환된다. (일반적으로 생성자는 값을 리턴하지 않음)
function User(name) {
  // this = {};  (빈 객체가 암시적으로 만들어짐)
  
  // 새로운 프로퍼티를 this에 추가함
  this.name = name;
  this.isAdmin = false;
  // return this;  (this가 암시적으로 반환됨)
}

let user = new User("보라");  
// = let user = {
//   	name: "보라",
//   	isAdmin: false
//  };

alert(user.name); // 보라
alert(user.isAdmin); // false

 

생성자 함수 참고: https://ko.javascript.info/constructor-new#ref-1199

 

 

1. 프로토타입 (Prototype)

  • 자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어있고, 이 부모 객체를 프로토타입이라고 한다.
  • 생성자 함수로부터 생성된 객체들이 공유할 수 있는 속성과 메서드를 정의한다.
  • 쉽게 말하면 상위객체로 부터 상속 받은 것이라고 생각하면 됨!
function Person (name) {    // Person은 생성자 함수
  this.name = name;
} 

Person.prototype.introduce = function () {  
  return "Hello, I am " + `${this.name}`;
}
// introduce는 Person.prototype에 정의된 메서드로 생성자 함수인 Person객체들이 공유할 수 있다.

const person1 = new Person("Jonh Doe");     
person1.introduce();  // Hello, I am John Doe

// 따라서 person1은 introduce 메서드를 상속받아 사용할 수 있다!
// person1은 'instance'
function User(first, last) {
  this.firstName = first
  this.lastName = last
}
User.prototype.getFullName = function () {
  return `${this.fistName} ${this.lastName}`
}
// firstName, lastName은 user함수가 실행될 때 마다
// 다른내용이 들어오기때문에 통일해서 메모리 관리를 할 수 없다.
// getFullName은 로직이 똑같기 때문에 여러번 작성하지 않고 통일화해서 관리

const john = new User('John', 'Doe') 
const amy = new User('Amy', 'Clarke')

console.log(john.getFullName)  // John Doe
console.log(amy.getFullName)  // Amy Clarke

 

2. 인스턴스 (Instance)

  • new 키워드를 통해 생성자 함수로 실행한 결과를 반환해서 할당된 그 변수를 생성자 함수의 instance 라고 한다.
  • instanceof 연산자를 사용해, 객체가 특정 생성자 함수의 인스턴스인지 확인할 수 있다.
function User(first, last) {
  this.firstName = first
  this.lastName = last
}
User.prototype.getFullName = function () {
  return `${this.fistName} ${this.lastName}`
}

const john = new User('John', 'Doe') 
const amy = new User('Amy', 'Clarke')   // john, amy는 User의 instance.

console.log(john.getFullName)  // John Doe
console.log(amy.getFullName)  // Amy Clarke

console.log(john instanceof User);  // true
console.log(amy instanceof User); // true

여기서 john과 amy가 생성자 함수 User의 instance이고, User의 프로토타입 체인을 따라 메서드와 속성을 상속받는다.

 

 

📌 Class

  • ES6 부터 사용할 수 있게 된 클래스는 생성자 함수와 프로토타입 메서드를 보다 직관적으로 작성할 수 있게 한다.
  • prototype을 사용해서 new라는 키워드와 함께 생성자 함수로 인스턴스를 만들어 내는 개념
  • 객체를 생산하는(찍어내는) 의미에서 붕어빵 틀에 자주 비유된다.

 

이걸 듣을 때 마다 내 머리 속 : ​

맛있겠다 ...🤤

 

 

1. class의 사용법

  • class 키워드 + 이름 + 중괄호
  • 클래스의 결과물은 인스턴스를 생성하는것.
  • 생성자를 이용한 타입 생성과 그 결과가 정확하게 일치한다.
function User(first, last) {
  this.firstName = first
  this.lastName = last
}
User.prototype.getFullName = function () {
  return `${this.fistName} ${this.lastName}`
}

const john = new User('John', 'Doe') 
const amy = new User('Amy', 'Clarke')

console.log(john.getFullName)  // John Doe
console.log(amy.getFullName)  // Amy Clarke

 

프로토타입 설명에서 작성된 위의 함수를 Class 문법으로 다시 작성 ↓

class User {
  constructor(first, last) {
    this.firstName = first
    this.lastName = last
  }
  getFullName() {   // 위처럼 prototype 사용하지 않고 정의가능.
    return `${this.fistName} ${this.lastName}`
  }
}

const john = new User('John', 'Doe') 
const amy = new User('Amy', 'Clarke')
// new라는 키워드를 통해서 생성자 함수로 실행한 결과를 반환해서 할당된 그 변수를
// 생성자 함수의 instance라고 부름. (여기서는 john,amy가 instance에 해당)

console.log(john.getFullName)  // John Doe
console.log(amy.getFullName)  // Amy Clarke

 

class 참고: https://typescript-kr.github.io/pages/classes.html

 

 

2. class 상속하기

  • extends 키워드를 사용해 class를 상속 받는다. (extend: 확장)
  • 상속받은 기존 클래스의 기능을 재사용, 필요에 따라 자식 클래스에서 기능을 추가하거나 변경 할 수도 있다.
    (= 메소드 오버라이딩)
  • 코드의 재사용성과 유지보수성이 높아짐.
class Vehicle {
  constructor(name, wheel) {
    this.name = name
    this.wheel = wheel
  }
}
const myVehicle = new Vehicle('운송수단', 2)
console.log(myVehicle)
// {
//    "name": "운송수단",
//    "wheel": 2
//  }


class Bicycle extends Vehicle {
  constructor(name, wheel) {
    super(name, wheel) 
// 1.확장된 Vehicle이 여기서 실행되므로 super의 인수로 사용되는
// name, wheel은 Vehicle의 constructor(name, wheel)로 가게됨.
// 2.위에서 '운송수단', 바퀴의 개수(2)를 넣어준 것처럼 인수를 넣어주면
// 함수영역안의 constructor(name, wheel)로 받아서 다시 super(name, wheel)로 넘겨줌.
// 3. 1의 설명처럼 super은 확장된 Vehicle이기 때문에 Vehicle의 내용이 실행됨.
  }
}
const myBicycle = new Bicycle('삼천리', 2)
const daughterBicycle = new Bicycle('세발', 3)
console.log(myBicycle)
console.log(daughterBicycle)

// {
//    "name": "삼천리",
//    "wheel": 2
//  }

// {
//    "name": "세발",
//    "wheel": 3
//  }

 

class Bicycle extends Vehicle 

⇒ 여기서 Vehicle을 부모 클래스(슈퍼 클래스), Bicycle을 자식 클래스(서브 클래스) 라고 한다. 

 

super (name, wheel)

⇒ super(): 부모 클래스(슈퍼 클래스)의 constructor를 호출한다.

 

// 기존의 내용을 가지고 추가적인 내용만 일부 작성한 예시
class Car extends Vehicle {
  constructor(name, wheel, license) {
    super(name, wheel)
    this.license = license
  }
}
const myCar = new Car('벤츠', 4, true)
const daughtersCar = new Car('포르쉐', 4, false)
console.log(myCar)
console.log(daughtersCar)
💡 메서드 오버라이딩
 부모클래스의 메서드를 내가 새롭게 정의하는 것

 

클래스 상속 참고: https://ko.javascript.info/class-inheritance

 

 

3. Private 

  • 변수앞에 _ (언더스코어)를 붙이면 'class 안에서만 쓰겠다'는 접근제어, 읽기 전용의 의미
    ⇒  but 강제사항이 아니기 때문에 언더스코어를 사용해도 변경이 가능
  • 이를 막기 위해서 JS에서는 _ 대신 #을 사용한다.
    ⇒  개발자 도구에서는 #을 했어도 접근이 가능하기 때문에 html파일에서 실행 추천
  • TS에서는 _ 대신 private을 사용한다.
  • 객체 안의 중요한 정보를 안전하게 보호하여 프로그램이 뜻하지 않게 변경되는 것을 막는 역할
class Car {
	#apiKey = '1234'   // 접근제어
}
💡 private과 public을 나누는 이유: 불필요한 부분이나 세부적인 기밀까지 사용자에게 노출되는 것을 막기 위해

 

private 메서드,프로퍼티 참고: https://ko.javascript.info/private-protected-properties-methods