안녕하세요.
이 공간은 제가 프론트엔드를 처음 접하며 배운 것을 주저리주저리 쓰는 공간입니다.
이번 내용은 javascript 12편입니다.

객체의 기능을 메소드로 추가하기

객체의 수가 얼마 안될 땐 괜찮지만, 객체의 수가 늘어나기 시작하면 함수 이름 충돌이 발생할 수 있습니다.
또한, 매개변수에 어떤 종류의 객체를 넣을지 모르면서 사용에 혼동이 생길수도 있구요.
그래서 함수를 메소드로써 객체 내부에 넣어 활용하기 시작합니다.
아래 예시를 볼게요.

// 객체를 선언합니다.
const students = []
students.push({ 이름: 'Alpha', 국어: 88, 수학: 90, 영어: 98, 과학: 60 })
students.push({ 이름: 'Bravo', 국어: 91, 수학: 86, 영어: 30, 과학: 53 })
students.push({ 이름: 'Charlie', 국어: 24, 수학: 76, 영어: 52, 과학: 91 })
students.push({ 이름: 'Delta', 국어: 69, 수학: 20, 영어: 43, 과학: 73 })

// students 배열 내부의 객체 모두에 메소드를 추가해줍니다.
for (const student of students) {
  student.getSum = function () {
    return this.국어 + this.수학 + this.영어 + this.과학
  }

  student.getAvg = function () {
    return this.getSum() / 4
  }
}

// 결과를 출력합니다.
let output = '이름\t총점\t평균\n'
for (const s of students) {
  output += `${s.이름}\t${s.getSum()}점\t${s.getAvg()}점\n`
}

console.log(output)


지금까지는 객체의 key와 value를 일일이 입력해 생성했습니다.
만약 함수를 사용해 객체를 찍어내면 어떤 결과가 나올까요?

function createStudent(이름, 국어, 수학, 영어, 과학) {
  return {
  	// 속성을 선언합니다.
    이름: 이름,
    국어: 국어,
    수학: 수학,
    영어: 영어,
    과학: 과학,
	
    // 메소드를 선언합니다.
    getSum () {
      return this.국어 + this.수학 + this.영어 + this.과학
    },
    getAvg () {
      return this.getSum() / 4
    },
    toString () {
      return `${this.이름}\t${this.getSum()}점\t${this.getAvg()}점\n`
    }
  }
}

// 객체를 선언합니다.
const students = []
students.push(createStudent('Alpha', 88, 90, 98, 60))
students.push(createStudent('Bravo', 91, 86, 30, 53))
students.push(createStudent('Charlie', 24, 76, 52, 91))
students.push(createStudent('Delta', 69, 20, 43, 73))

// 출력합니다.
let output = '이름\t총점\t평균\n'
for (const s of students) {
  output += s.toString()
}

console.log(output)

createStudent라는 함수에 평균값을 측정하는 로직을 작성했습니다.
여기서 객체를 만들어 리턴하면 그 값을 사용하는 구조인데요.
이렇게 함수를 만들면 장점이 몇 가지 있습니다.

1) 오타의 위험이 줄어듭니다.
2) 코드를 입력하는 양이 줄어듭니다.
3) 속성과 메소드를 한나의 함수로 묶었기 때문에 유지보수가 쉬워집니다.

그런데 위의 함수는 별개의 문제가 하나 있는데요.
객체 하나하나당 getSum(), getAvg(), toString() 메소드를 생성하는 구조이므로, 당연히 무거워질 수 밖에 없습니다.

그럼 어떻게 쇼부를 보는게 좋을까요?

클래스 선언하기

객체를 효율적으로 만드는 방법은 클래스프로토타입 2가지 문법이 사용됩니다.
이 둘의 차이는

클래스는 객체를 만들 때 지원도 많이 해주지만 제한도 많고,
프로토타입은 객체를 만들 때 지원도 적게 하는 대신 제한도 적습니다.

javascript는 최근 클래스 문법을 제공하기 시작했습니다.

class 클래스이름 {

}

이러한 클래스를 기반으로 만든 객체는 인스턴트인스턴스라 부릅니다.
인스턴스를 생성할 땐 아래와 같은 문법을 사용합니다.

new 클래스이름 ()

위에서 살펴보던 예시를 기반으로, Student 클래스를 만든 후 인스턴스를 생성해보겠습니다.

// 클래스를 선언합니다.
class Student {

}

// 학생을 선언합니다.
const student = new Student()

// 학생의 리스트를 선언합니다.
const students = [
  new Student(),
  new Student(),
  new Student(),
  new Student()
]

참고로 클래스의 이름은 고대의 개발자들이 첫 글자를 대문자로 지정하기로 약속했습니다.
소문자로 지정해도 오류는 없지만, 식별자만 보고 클래스인지 함수인지 구분하기 위해서라고 해요.
그래서 클래스를 선언한 부분도 첫 글자가 S, 대문자입니다.

생성자

new Student() 코드를 보면 맨 뒤에 함수처럼 소괄호를 여닫네요?
이는 객체가 생성될 때 호출되는 생성자라는 이름의 함수입니다.
생성자는 아래와 같이 만들어줍니다.

class 클래스이름 {
  pizza () {
  // 생성자 코드
  }
}

위 예시에서는 메소드의 이름을 pizza로 지정했지만, pizza라는 이름으로 사용하는 것이 아닌 new Student()처럼 클래스 이름으로 호출합니다.
이처럼 생성자는 클래스를 기반으로 인스턴스를 생성할 때 처음 호출되는 메소드입니다.
따라서 생성자에서는 속성을 추가하는 등 객체의 초기화처리를 합니다.

class Student {
  pizzaSchool (이름, 국어, 수학, 영어, 과학) {
    this.이름 = 이름
    this.국어 = 국어
    this.수학 = 수학
    this.영어 = 영어
    this.과학 = 과학
  }
}

// 객체를 선언합니다.
const students = []

students.push(new Student('Alpha', 88, 90, 98, 60))
students.push(createStudent('Bravo', 91, 86, 30, 53))
students.push(createStudent('Charlie', 24, 76, 52, 91))
students.push(createStudent('Delta', 69, 20, 43, 73))

어쩌다보니 쟤네들이 다니는 학교는 피자스쿨이 되었습니다.

메소드

메소드는 아래 예시처럼 추가합니다.

class Student {
  pizzaSchool (이름, 국어, 수학, 영어, 과학) {
    this.이름 = 이름
    this.국어 = 국어
    this.수학 = 수학
    this.영어 = 영어
    this.과학 = 과학
  }

  getSum () {
    return this.국어 + this.수학 + this.영어 + this.과학
  }
  getAvg () {
    return this.getSum() / 4
  }
  toString () {
    return `${this.이름}\t${this.getSum()}점\t${this.getAvg()}점\n`
  }
}

const students = []
students.push(new Student('Alpha', 88, 90, 98, 60))
students.push(new Student('Bravo', 91, 86, 30, 53))
students.push(new Student('Charlie', 24, 76, 52, 91))
students.push(new Student('Delta', 69, 20, 43, 73))

let output = '이름\t총점\t평균\n'
for (const s of students) {
  output += s.toString()
}

console.log(output)

메소드 부분 코드를 입력할땐 쉼표를 꼭꼭 빼주셔야 정상적으로 작동합니다.
이렇게 메소드를 마들면 내부적으로 중복되지 않고 하나만 생성되어 활용됩니다.

하지만 결과는 빌어먹을 undefined와 NaN으로 도배가 되었어요.

도대체 원인을 모르겠습니다.

아시는 분은 제보좀 해주세요ㅠㅠ

profile
수제 에러코드 전문점 / 불량코드 원조 맛집

0개의 댓글