connecting dots

JS 클래스 | 생성자 함수(prototype), this, ES6 classes, 상속(확장) 본문

Online Class/DevCamp

JS 클래스 | 생성자 함수(prototype), this, ES6 classes, 상속(확장)

dearsuhyun 2024. 6. 12. 11:13

생성자 함수(prototype)

const heropy = {
  firstName: 'Heropy',
  lastName: 'Park',
  getFullName: function () {
    return `${this.firstName} ${this.lastName}`
  }
}
console.log(heropy.getFullName()) //Heropy Park

// this = this가 소속되어져 있는 부분에 함수가 실행되는
// 그 객체 데이터(heropy)를 지칭함 (heropy.firstName이랑 같음)

const amy = {
  firstName: 'Amy',
  lastName: 'Clark',
  getFullName: function () {
    return `${this.firstName} ${this.lastName}`
  }
}
console.log(amy.getFullName()) // Amy Clark

const neo = {
  firstName: 'Neo',
  lastName: 'Smith',
  getFullName: function () {
    return `${this.firstName} ${this.lastName}`
  }
}
console.log(neo.getFullName()) // Neo Smith

 

--> 로직은 같은데 객체 데이터가 각각 있으니 메모리 효율이 떨어짐

--> 클래스 사용 !

 

function user(first, last) {
  this.firstName = first
  this.lastName = last
}

const heropy = new user('heropy', 'Park');
// user: 생성자함수. 하나의 객체데이터를 생성하는 것임
const amy = new user('Amy', 'Clarke')
const neo = new user('Neo', 'Smith')

console.log(heropy) // user {firstname: "Heropy", lastname: "Park"}
console.log(amy)
console.log(neo)

// { } 중괄호, [ ] 대괄호, "" 등 
// 기호를 가지고 데이터를 만드는 방식 = 리터럴 방식

 

new라는 키워드를 통해서 생성자 함수로 실행한 결과를 반환해서 할당된 그 변수

--> heropy, amy, neo = 생성자 함수의 instance

 

function User(first, last) {
  this.firstName = first
  this.lastName = last
}

User.prototype.getFullname = function () {
  return `${this.firstName} ${this.lastName}`
}

const heropy = new User('heropy', 'Park');
const amy = new User('Amy', 'Clarke')
const neo = new User('Neo', 'Smith')

console.log(heropy.getFullname())
console.log(amy.getFullname())
console.log(neo.getFullname())

// 위에 prototype 함수를 참조하는 것임

 

다른 함수와 구분하기 위해 파스칼 케이스로 작성 function User ...

 

this

일반 함수 내부에서는 호출 위치에 따라 this 정의

화살표 함수에서는 자신이 선언된 함수 범위에서 this 정의

const heropy = {
  name: 'Heropy',
  normal: function () {
    console.log(this.name)
  },
  arrow: () => {
    console.log(this.name)
  }
}
heropy.normal() //Heropy
heropy.arrow() //Undefined
// 함수 호출, 두개는 메소드라고 부름. 앞에 객체 붙어있기 때문에

 

normal이 호출되는 위치에서 함수가 정의됨

heropy 객체 데이터 안에서 실행됨. 즉 호출된 위치에서 앞에 있는 객체 데이터는 heropy

heropy가 . 곧 this이고 그 안에서 name을 꺼내 쓰는 것임 !

 

화살표 함수가 자신이 선언된 어떤 범위가 존재하거나 그 범위 외부에 함수가 보이지 않음.

화살표 함수로 this 사용할 때 알 수없는 부분에서 name을 찾으려고 하기 때문에 undefined

 

const amy = {
  name: 'Amy',
  normal: heropy.normal,
  arrow: heropy.arrow
} 
// 호출하는 개념이 아니라 normal의 함수 자체가 amy의 normal, arrow에 할당

amy.normal()
// Amy
// 호출위치에서 정의, 연결된 객체는 amy니까 amy가 곧 this이고 this 부분의 name이 Amy라서 Amy출력됨
amy.arrow()
// Undefined

 

prototype과 this

function User(name) {
  this.name = name
}
User.prototype.normal = function () {
  console.log(this.name)
}
User.prototype.arrow = () => {
  console.log(this.name)
}

const heropy = new User('Heropy')

heropy.normal() // Heropy
heropy.arrow() // undefined

 

setTimeout, setInterval의 경우 콜백함수 보다는 일반함수가 좋음 !

const timer = {
  name: 'heropy',
  timeout: function () {
    setTimeout(() => {
      console.log(this.name) 
      //일반함수일 경우 setTimeout 함수의 로직으로 들어감
      // timer라는 객체 데이터의 name 부분으로 지칭해서 출력하기 원하기 때문에 화살표 함수 사용
    }, 2000)
  }
}
timer.timeout() // Heropy


function 부분에 this는 timer라는 객체 데이터를 가리키기 때문에 여기서의 this는 결국 timer가 됨

 

ES6 classes

객체 데이터 내부에서 일반 함수를 사용할 때는 ': function'을 생략해줄 수 있음

const heropy = {
  name: 'heropy',
  normal() {
    console.log(this.name)
  },
  arrow: () => {
    console.log(this.name)
  }
}

heropy.normal() // heropy
heropy.arrow() // undefined


class 키워드 사용

function User(first, last) {
   this.firstName = first
   this.lastName = last
 }

User.prototype.getFullname = function () {
   return `${this.firstName} ${this.lastName}`
 }

 

class User {
  constructor(first, last) {
    this.firstName = first
    this.lastName = last
  }
  getFullname() {
    return `${this.firstName} ${this.lastName}`
  }
}

const heropy = new User('heropy', 'Park');
const amy = new User('Amy', 'Clarke')
const neo = new User('Neo', 'Smith')

console.log(heropy) // 
console.log(amy.getFullname()) // Amy Clark
console.log(neo.getFullname()) // Neo Smith


constructor 내부 함수 사용, 리액트에서 많이 사용함

 

ES6 클래스는 객체 지향 프로그래밍(OOP)을 보다 쉽게 구현할 수 있도록 도와줍니다. 여기서 ES6 클래스에 대해 쉽게 설명해드리겠습니다.
클래스 정의


클래스는 객체를 생성하기 위한 템플릿입니다. ES6 이전에는 함수와 프로토타입을 사용하여 객체를 정의했습니다. ES6 클래스 문법은 이를 더 직관적이고 간결하게 만들어줍니다.

class User {
  // 생성자 함수, 새로운 객체가 생성될 때 호출됩니다.
  constructor(firstName, lastName) {
    this.firstName = firstName; // 인스턴스 변수 정의
    this.lastName = lastName;   // 인스턴스 변수 정의
  }

  // 메서드 정의, 모든 User 인스턴스에서 사용할 수 있습니다.
  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

// 새로운 User 객체 생성
const user1 = new User('John', 'Doe');

// 메서드 호출
console.log(user1.getFullName()); // "John Doe"​


주요 개념 설명


1. 클래스 선언:
class User { ... }를 사용하여 User라는 클래스를 선언합니다.
2. 생성자 메서드 (constructor):
constructor(firstName, lastName)는 객체가 생성될 때 호출됩니다.
생성자 함수 안에서 this.firstName = firstName;과 같이 객체의 속성을 초기화합니다.
3. 메서드 정의:
getFullName() 메서드는 클래스 내에 정의되며, 모든 인스턴스에서 사용 가능합니다.
this 키워드를 사용하여 인스턴스 속성에 접근합니다.

 

상속(확장)

class Vehicle {
  constructor(name, wheel) {
    this.name = name
    this.wheel = wheel
  }
}
const myVehicle = new Vehicle('운송수단', '2')
console.log(myVehicle)


// 확장(상속)
class Bicycle extends Vehicle {
  constructor(name, wheel) {
    super(name, wheel)
  }
}
const myBicycle = new Bicycle('삼천리', 2)
const daughterBicycle = new Bicycle('세발', 2)
console.log(myBicycle)
console.log(daughterBicycle)

 

super는 extends 키워드 뒤에 붙어잇는 vehicle을 의미

super가 있는 그 자리에서 vehicle 실행됨

bicycle 클래스가 실행되는 부분에서 인수를 넣어주면 그것을 super로 넘겨줌

즉 인수가 vehicle로 들어가서 사용되는 것과 같음

 

class Car extends Vehicle {
  constructor(name, wheel, licence) {
    super(name, wheel) // Vehicle 의미
    this.liscense = liscense
  }
}
const myCar = new Car('벤츠', 4, true)
const daughterCar = new Car('포르쉐', 4, false)
console.log(myCar)
console.log(daughterCar)

 

추가적인 내용(licence) 일부 작성하여 확장하고 발전 가능

 

상속 (Inheritance)


클래스는 다른 클래스를 상속받아 기능을 확장할 수 있습니다. 이를 통해 코드 재사용성을 높일 수 있습니다.

class User {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

class Admin extends User {
  constructor(firstName, lastName, role) {
    super(firstName, lastName); // 부모 클래스의 생성자를 호출합니다.
    this.role = role;           // 새로운 속성을 추가합니다.
  }

  getRole() {
    return this.role;
  }
}

const admin1 = new Admin('Alice', 'Johnson', 'supervisor');
console.log(admin1.getFullName()); // "Alice Johnson"
console.log(admin1.getRole()); // "supervisor"​


주요 개념 설명


1. 상속:
class Admin extends User { ... }를 사용하여 User 클래스를 상속받는 Admin 클래스를 선언합니다.
2. super() 호출:
super(firstName, lastName);는 부모 클래스(User)의 생성자를 호출합니다.
이를 통해 부모 클래스의 속성을 초기화할 수 있습니다.
3. 새로운 메서드 추가:
Admin 클래스에 getRole() 메서드를 추가하여 역할(role)을 반환합니다.

반응형