자바스크립트 - 클래스 기본

2023. 1. 2. 05:31웹개발 메모장

728x90
SMALL
더보기

혼자 공부하는 자바트스크립트 9-1 : 클래스의 기본 기능

 

- 위의 책 내용을 바탕으로 공부하고 알아본 내용을 정리하는 시간

 

 

 수많은 프로그래밍 언어가 있는데 그 중에서 C언어를 제외한 모든 프로그래밍 언어는 객체 지향이라는 패러다임을 기반으로 만들어졌다.
객체 지향 패러다임은 객체를 우선적으로 생각해서 프로그램을 만든다는 방법론인데, 이 객체 지향 프로그래밍 언어들은 클래스 라는 문법으로 객체를 효율적이고 안전하게 만들어 객체 지향 패러다임을 쉽게 프로그래밍에 적용할 수 있도록 도와준다. "혼자스" 9 - 1 에서는 앞에서 배운 방법으로 객체 지향 프로그래밍 방법을 배우고, 클래스 문법이 어떤 형태로 구성되는지 배우게 된다.

 

 

 


 

추상화

; 프로그램에 필요한 요소만 사용해서 객체를 표현하는 것을 추상화라고 한다. 좀 더 포괄적인 사전적 의미로 복잡한 자료, 모듈, 시스템 등으로 부터 핵심적인 개념과 기능을 산추려내는 것을 추상화라고 한다.

 

https://youtu.be/DiZ4_cotA6s

학생 성적 관리 프로그램을 만들 때, 학생의 모든 정보를 적는 것이 아니라 필요한 정보만 추출하여 만드는데 여러 학생들의 성적관리에 필요한 공통사항을 추출하는 것을 추상화라고 한다. 

책을(유니코딩 유투브) 통한 예시를 가져왔다.

 

 

같은 형태의 객체 만들기

 

<script>

//객체를 선언한다.
const student = []
students.push({이름: '구름', 국어: 87, 영어: 98, 수학: 88, 과학: 90})
students.push({이름: '별이', 국어: 92, 영어: 98, 수학: 96, 과학: 88})
students.push({이름: '겨울', 국어: 76, 영어: 96, 수학: 94, 과학: 86})
students.push({이름: '바다', 국어: 98, 영어: 52, 수학: 98, 과학: 92})

//출력한다
alert(JSON.stringify(students, null, 2))
</script>

JSON.stringfy()

객체를 JSON 문자열로 변환할 때 사용하는 메소드이다.

 

 

위 코드에서 이제 학생별 성적 총합과 평균을 구해보도록하자

 

<script>

//객체를 선언한다.
const student = []
students.push({이름: '구름', 국어: 87, 영어: 98, 수학: 88, 과학: 90})
students.push({이름: '별이', 국어: 92, 영어: 98, 수학: 96, 과학: 88})
students.push({이름: '겨울', 국어: 76, 영어: 96, 수학: 94, 과학: 86})
students.push({이름: '바다', 국어: 98, 영어: 52, 수학: 98, 과학: 92})

//출력한다
let output = '이름\t총점\t평균\n'
fot (const s of students) {
	const sum = s.국어 + s.영어 + s.수학 + s.과학
    const average = sum / 4
    output += `${s.이름}\t${s.sum}점\t${s.average}점\n`
}
console.log(output)
</script>
\t 	// 탭 tap 키역할
\n	 // 줄바뀜 enter 키역할

객체를 처리하는 함수 만들기

이제 객체를 처리하는 함수를 만들어본다.

 

총합과 평균을 구하는 기능은 성적관리 프로그램 외에도 여러 프로그램에서 쓰일 수 있으니 단순한 계산 코드보다 함수를 만들어 사용하는 것이 확장성을 고려했을 때 좋은 방법이다.

 

그래서 우리는 위의 코드에서 함수를 만들어 다시 적용 시킬 예정이다.

getSumOf() 총합 구하는 함수
getAverageOf() 평균 구하는 함수

 

 

<script>

//객체를 선언한다.
const student = []
students.push({이름: '구름', 국어: 87, 영어: 98, 수학: 88, 과학: 90})
students.push({이름: '별이', 국어: 92, 영어: 98, 수학: 96, 과학: 88})
students.push({이름: '겨울', 국어: 76, 영어: 96, 수학: 94, 과학: 86})
students.push({이름: '바다', 국어: 98, 영어: 52, 수학: 98, 과학: 92})

//객체를 처리하는 함수를 선언한다.
function getSumOf (student) {
	return student.국어 + student.영어 + student.수학 + student.과학
}

function getAverageOf (student){
	return getSumOf(student)/4
}

//출력한다
let output = '이름\t총점\t평균\n'
fot (const s of students) {
	output += `${s.이름}\t${getSumOf(s)}점\t${getAverageOf(s)}점\n`
}
console.log(output)
</script>

결과는 위에 단순 계산한 코드와 같다.

여기까지 보면 코드만 길어졌지 결과가 똑같으니 의아할 수 있다. 나 역시도 코드가 오히려 더 길어졌다고 생각했고 굳이? 라는 생각이 들었다. 그러나 이렇게 해두면 나중에 개게를 쉽게 유지보수 할 수 있고, 객체를 활용할 때도 더 간단하게 코드를 작성할 수 있다고 한다.

 

 

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

 

지금까지 만든 코드는 학생이라는 객체 하나라서 괜찮지만 객체 수가 늘어나면 함수 이름 충돌이 일어날 수 있다.

그래서 함수를 메소드로써 객체 내부에 넣어서 활용하는 방법을 사용하기로 한다.

 

<script>

//객체를 선언한다.
const student = []
students.push({이름: '구름', 국어: 87, 영어: 98, 수학: 88, 과학: 90})
students.push({이름: '별이', 국어: 92, 영어: 98, 수학: 96, 과학: 88})
students.push({이름: '겨울', 국어: 76, 영어: 96, 수학: 94, 과학: 86})
students.push({이름: '바다', 국어: 98, 영어: 52, 수학: 98, 과학: 92})

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

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

//출력한다
let output = '이름\t총점\t평균\n'
fot (const s of students) {
	output += `${s.이름}\t${getSum()}점\t${getAverage()}점\n`
}
console.log(output)
</script>

 

이렇게 코드를 짜면 결과는 위와 같지만 함수 이름 충돌이 발생하지 않고, 함술르 잘못 사용하는 경우도 줄일 수 있다.

 

그동안 캑체의 키와 값을 하나하나 입력해서 생성했는데,

이제는 함수를 사용해서 객체를 찍어내는 코드를 만들어보려고 한다.

 

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

//객체를 선언한다.
const students = []
students.push(createStudent('구름', 87, 98, 88, 90))
students.push(createStudent('별이', 92, 98, 96, 88))
students.push(createStudent('겨울', 76, 96, 94, 86))
students.push(createStudent('바다', 98, 52, 98, 92))

//출력한다.
let output = '이름\t총점\t평균\n'
fot (const s of students) {
	output += s.toString()
}
console.log(output)
</script>

위 코드는 createStudent 함수를 만들고, 여기에 객체를 만들어서 리턴하게 만들었다.

 

이렇게 함수를 만들면 객체를 하나하나 만들 때와 비교했을때,

오탈자의 위험이 줄어들고

코드를 입력하는 양이 크게줄어든다.

그리고 속성과 메소드를 한 함수 내부에서 관리할 수 있어서 객체를 더 손쉽게 유지보수 할 수 있다.

 

 

But!

함수를 메소드로 사용하면서 객체 내부에 넣어 활용하는 방법을 배웠는데, 장점이 많아졌지만 객체별로 getSum() , getAverage(), toString()  메소드를 생성하면서 함수라는 기본 자료형보다 무거운 자료형을 여러번 생성하게 됐다.

 

 

그래서 이 문제를 해결하고 효율적인 객체 지향 언어 형태로 프로그래밍하기 위해서 마련된 방법이 프로토타입과 클래스이다.

 

 

  • 프로토타입(Prototype)이란? 

프로토타입은 다른 객체를 가리키는 내부 링크로, 모든 자바스크립트 객체가 가지고 있다. 이러한 프로토타입으로 직접 객체를 연결할 수 있는데, 이를 '프로토타입 체인'이라고 한다. 이는 객체 지향 프로그래밍 특징 중 '상속'과 관련되어 있으며, 매번 새롭게 속성과 메소드를 정의할 필요 없이 작성된 메소드를 그대로 사용할 수 있게 해준다.

 

  • 클래스(Class)란?

클래스는 어떠한 대상의 설계도, 혹은 청사진(blue print) 이라고 할 수 있으며, 인스턴스는 이러한 설계도를 바탕으로 실제 제작된 객체라고 볼 수 있다. 클래스는 객체 지향 프로그래밍에서 특정 객체를 생성하기 위해 변수와 메소드를 정의하는 일종의 틀로, 객체를 정의하기 위한 상태(멤버 변수)와 메서드(함수)로 구성된다.

 

 

 

현재 사용되는 대부분의 갹체 지향 프로그래밍 언어는 클래스문법을 제공한다. 자바스크립트는 초기에 프로토타입 문법을 제공했지만 현재는 클래스 문법을 제공하기 시작했다.

 

 

 

* 클래스를 기반으로 만든 객체는 전문 용어로 인스턴스하고 한다. 그냥 객체라고 부르는 경우도 많다.

 

클래스 선언하기

 

클래스란?

연관 있는 데이터들을 한군데 모아 놓는 컨테이너 같은 역할을 한다.

// 클래스 선언
class Person {
    name; // 프로퍼티(혹은 속성(filed))
    age; // 프로퍼티(혹은 속성(filed))
    speak(); // 메소드
}

// 객체 생성
// 객체를 생성할 때는 클래스앞에 new라는 키워드를 사용한다.
const kim = new Person('Kim', 27);
console.log(Kim.name);
console.log(Kim.age);

자바스크립트에서 클래스의 ES6에서 소개되었다.

그전에는 클래스를 정의하지 않고 객체를 정의해서 사용하는 방법이 있었고

객체를 만들때 함수를 이용해서 템플릿(클래스 같은 역할)을 만드는 방법이 있었다.

 

 

인스턴스(객체) 클래스
  • instanc of a class, 클래스의 인스턴스이다.
  • 1개의 클래스로 여러개의 객체를 만들수 있다.
  • 객체 안에는 데이터가 있다.
  • 메모리에 올라간다.
  • template, 즉 틀 같은 역할을 한다.
  • 한번만 선언한다.
  • 클래스 안에는 데이터가 없다.
  • 메모리에 올라가지 않는다.

클래스는 타코야끼 틀, 
객체는 클래스(타코야끼 틀)로 찍어낸 타코야끼. 즉, 클래스를 정의해서 다양한 객체들을 만든다.

책에서는 붕어빵과 붕어빵틀에 비유했지만, 나는 타코야끼를 좋아하니까 타코야끼 틀로 비유했다ㅎㅎ 

 

 

 

  • 클래스 : 이전에 살펴보안던 객체를 만드는 함수와 비슷한 것
  • 인스턴스(객체) : 이전에 만들었던 객체를 만드는 함수로 만든 객체와 비슷한 것
주의사항 //

클래스 이름은 첫글자를 대문자로 지정할 것!
(이는 개발자들 간의 약속으로 식별자만 보고도 이것이 클래스라는 것을 바로 알 수 있도록 한 것이다.) 

 

 

클래스 선언 & 인스턴드 생성

// 클래스 
class 클래스 이름 {

}

// 인스턴스를 생성할 때
new 클래스 이름()

 위 코드를 참고하여 클래스를 선언하고 인스턴스를 생성해 보자.

 

 

<script>
	//클래스를 선언한다.
	class Student {
    
    }
    
    //학생을 선언한다.
    const student = new Student()
    
    //학생 리스트를 선언한다.
    const students = [
    	new Student(),
        new Student(),
        new Student(),
        new Student()
    ]

</script>

 

생성자

 

생성자란?

생성자는 클래스를 기반으로 인스턴스를 생성할 때 처음으로 호출되는 메소드이다.

new Student()라는 코드를 보면 함수처럼 뒤에 괄호가 붙어있다.  이것은 객체가 생성될 때 호출되는 생성자라는 이름의 함수이다.

 

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

* 메소드의 이름을 constructor로 지정했지만 new Student()처럼 클래스 이름으로 호출한다.

 

<script>
	class Student {
    	constructor (이름, 국어, 영어, 수학, 과학) {
    	this.이름 = 이름
        this.국어 = 국어
        this.영어 = 영어
        this.수학 = 수학
        this.과학 = 과학
        }
    }
    
//객체를 선언한다.
const students = []
students.push(new Student('구름', 87, 98, 88, 90))
students.push(new Student('별이', 92, 98, 96, 88))
students.push(new Student('겨울', 76, 96, 94, 86))
students.push(new Student('바다', 98, 52, 98, 92))

//출력한다.
let output = '이름\t총점\t평균\n'
fot (const s of students) {
	output += s.toString()
}
console.log(output)
</script>

 

 

메소드

 

마지막으로 다음과 같이 메소드를 만들면 끝이 난다.

이렇게하면 메소드가 중복되지 않고 하나만 생성되어 활용된다.

 

<script>
	class Student {
    	constructor (이름, 국어, 영어, 수학, 과학) {
    	this.이름 = 이름
        this.국어 = 국어
        this.영어 = 영어
        this.수학 = 수학
        this.과학 = 과학
        }
    }
    
    getSum () {
    	return this.국어 + this.영어 + this.수학 + this.과학
    }
    getAverage () {
    	return this.getSum() / 4
    }
    toString () {
    	return `${this.이름}\t${this.getSum()}점\t${this.getAverage()}점\n`
    }
}
    
//객체를 선언한다.
const students = []
students.push(new Student('구름', 87, 98, 88, 90))
students.push(new Student('별이', 92, 98, 96, 88))
students.push(new Student('겨울', 76, 96, 94, 86))
students.push(new Student('바다', 98, 52, 98, 92))

//출력한다.
let output = '이름\t총점\t평균\n'
fot (const s of students) {
	output += s.toString()
}
console.log(output)
</script>

여기까지 보면 아까 위에서 함수로 객체를 찍어내는 코드와 비슷하다고 생각할 수 있는데,

내부적으로 살펴보면 위에서 함수로 객체를 찍어내는 코드는 객체별로 계속 생성해내기 때문에 쓸데없는 용량을 차지하는데 반면,

지금 코드의 경우 모든 객체가 저 함수를 공유해서 사용하고 있기 때문에 내부적으로 용량에 무리가 가지 않는다.

이것을 공유함수(공유 프로시저)라고 한다.

 

 

 

▶️ 참고한 사이트

728x90
LIST