반응형
Class (클래스)
개념
ES5에서는 클래스가 없으며 객체형, 클로저, 생성자, 프로토타입 등을 이용해 클래스와 유사한 구조를 만들어 사용한다.
ES5와 다르게 ES6에서는 클래스 문법을 직접적으로 지원함.
내부적으로 Class는 격국 object형과 같다.
형식
<body>
<script>
class class_name {}
new class_name
</script>
</body>
선언과 인스턴스 생성
<body>
<script>
class CS
{
}
const a = new CS();
const aArray = [new CS(), new CS(), new CS()];
</script>
</body>
클래스의 생성자
constructor로 생성자를 호출한다.
ES6때 출현.
class cs {
constructor(){}
}
this를 통해 object에 변수를 등록한다. (object와 유사함.)
<body>
<script>
class student
{
constructor(_id = 0, _name = 0, _score = 0) //default parameter
{
this.id = _id;
this.name = _name;
this.score = _score;
}
};
const s1 = new student('JSR', '정상록', '100')
console.log(s1.id)
console.log(s1.name)
console.log(s1.score)
//JSR
//정상록
//100
</script>
</body>
* 생성자에 객체를 추가할 시 Shallow Copy(얕은 복사)에 주의한다.
<body>
<script>
class student
{
constructor(_id = 0, _name = 0, _score = 0)
{
this.id = _id;
this.name = _name;
this.score = _score;
}
};
const score = [100, 35, 88, 85]
const s1 = new student('JSR', '정상록', score);
console.log(s1.score);
score[0] = 50;
console.log(s1.score)
//(4) [100, 35, 88, 85]
//(4) [50, 35, 88, 85]
</script>
</body>
* Shallow copy(얕은 복사) 해결. (private 하단 참조)
<body>
<script>
class student
{
#id
#name
#score
constructor(_id = 0, _name = 0, _score = 0)
{
this.#id = _id;
this.#name = _name;
this.#score = [..._score];
}
getScore(){
return this.#score
}
};
const score = [100, 35, 88, 85]
const s1 = new student('JSR', '정상록',score);
console.log(s1.getScore());
//(4) [100, 35, 88, 85]
</script>
</body>
Method 추가
class의 method로 추가
- readability(가독성)이 좋다.
- 가장 기본적인 방법이다.
<body>
<script>
class student
{
constructor(_id = 0, _name = 0, _score = 0)
{
this.id = _id;
this.name = _name;
this.score = _score;
}
getId = function()
{
return this.id
}
};
const s1 = new student('220000', 'JSR', '정상록')
console.log(s1.getId())
//220000
</script>
</body>
Prototype을 사용한 Method 추가
- readability(가독성)이 떨어지는 치명적인 문제가 있다.
<body>
<script>
class student
{
constructor(_id = 0, _name = 0, _score = 0)
{
this.id = _id;
this.name = _name;
this.score = _score;
}
};
student.prototype.getId = function()
{
return this.id
}
const s1 = new student('220000', 'JSR', '정상록')
console.log(s1.getId())
//220000
</script>
</body>
인스턴스로 추가.
- readability(가독성)이 떨어지는 치명적인 문제가 있다.
<body>
<script>
class student
{
constructor(_id = 0, _name = 0, _score = 0)
{
this.id = _id;
this.name = _name;
this.score = _score;
}
};
student.prototype.getId = function()
{
return this.id
}
const s1 = new student('220000', 'JSR', '정상록')
s1.func = function()
{
console.log("Instance로 추가.")
}
</script>
</body>
문제
id, name, 3개의 score와 평균을 구하는 메서드를 가진 student 클래스를 구현하고자 한다.
각각의 장단점과 결론을 설명하시오.
- Object를 이용하여 구현하시오.
- constructor + prototype로 구현하시오.
- closure로 구현하시오.
- class로 구현하시오.
1. Object를 이용하여 구현하시오.
https://cruella-de-vil.tistory.com/38
<body>
<script>
//object를 이용하여 만들기
const student1 = {
getAv : function() {
let av = 0;
for (let val of this.score)
{
av = av + val;
}
return (av/this.score.length).toFixed(2);
}
};
const student2 = {
id : 'JO',
name : '조온',
score : [80, 70, 98],
getAv : function() {
let av = 0;
for (let val of this.score)
{
av = av + val;
}
return (av/this.score.length);
}
};
const score = [100, 90, 80]
student1.id = 'JSR'
student1.name = '정상록'
student1.score = score
//출력
console.log(student1.id)
console.log(student1.name)
console.log(student1.score)
console.log(student1.getAv().toFixed(2))
//JSR
//정상록
//(3) [100, 90, 80]
//90.00
</script>
</body>
장점 :
- 직관적이다.
- 코딩하기 쉽다.
- Shallow copy와 상관없이 독립적으로 데이터를 유지한다.
단점 :
- 인스턴스 추가시 추가적인 코드가 발생한다.
- 코드의 중복이 일어난다.
- 코드의 일관성이 없어질 수 있는 여지가 존재한다.
- 접근제어 기능이 부재하다.
결론 :
- 인스턴스가 3개 이상이 되는 경우 object 방식은 좋지 않다.
- 함수의 수가 다수 존재할수록 복잡해진다.
- 정보가 단순할 경우 사용한다.
- Singleton 패턴에서 사용한다.
2. Constructor + Prototype을 이용하여 구현하시오.
https://cruella-de-vil.tistory.com/52
https://cruella-de-vil.tistory.com/54
<body>
<script>
const student = function(_id, _name, _score)
{
this.id = _id;
this.name = _name;
this.score = [..._score] //spread
this.getTotal = function()
{
let total = 0;
for (let val of this.score)
{
total = total + val;
}
return total;
}
}
//prototype method 확장
student.prototype.getAverage = function()
{
let total = 0;
for (let val of this.score)
{
total = total + val;
}
return (total/this.score.length);
}
const score = [100, 87, 54]
const s1 = new student('JSR', '정상록', score)
const s2 = new student('JJ', '조조', [90, 70, 88])
//출력
console.log(s1.score)
console.log(s1.name)
console.log(s1.id)
console.log(s1.getAverage().toFixed(2))
//(3) [100, 87, 54]
//정상록
//JSR
//80.33
</script>
</body>
장점 :
- 객체의 생성부와 정의부가 분리된다. (중복제거, 가독성 증가...)
- 코드의 중복이 없다.
단점 :
- 메서드나 속성의 위치가 애매하다.
- this가 맥락에 따라 달라진다.
- 접근제어 기능이 부재하다. (No private) / 해결 : closure
결론 :
- 생성자로 사용할 시 method를 prototype으로 확장하지 않아도 된다.
3. closure로 구현하시오.
https://cruella-de-vil.tistory.com/53
<body>
<script>
//closure
const makeStudent = function (_id, _name, _score)
{
//Deep Copy 처리.
//L Val = R Val(우선처리)
_score = [..._score];
//기능 구현의 일관성이 떨어진다.
return {
getId() {
return _id;
},
setId(id) {
_id = id;
},
getName() {
return _name;
},
setName(name) {
_name = name;
},
getScore() {
return _score;
},
setScore(score, idx) {
_score[idx] = score;
},
getAverage() {
let total = 0;
for (let val of _score)
{
total = total + val;
}
return (total/_score.length);
}
}
}
const score = [90, 87, 77];
const st1 = makeStudent('JSR', '정상록',score)
console.log(st1.getScore())
console.log(st1.getId())
console.log(st1.getAverage().toFixed(1))
st1.setScore(100, 1)
console.log(st1.getScore())
console.log(st1.getAverage().toFixed(1))
//(3) [90, 87, 77]
//JSR
//84.7
//(3) [90, 100, 77]
//89.0
</script>
</body>
장점 :
- 접근 제어가 가능하다.
- 객체의 선언부와 정의부가 분리된다.
- 코드의 중복이 없다.
단점 :
- 문법적으로 어렵다. (내부 메커니즘 중 scope chain을 오용.)
- 기능 구현의 일관성이 없다.
결론 : ES5가 가지는 object, constructor, prototype, closure는 문제점과 한계가 존재한다.
4. Class를 이용하여 구현하시오.
<body>
<script>
//class를 이용하여 만들기
class student
{
constructor(_id = 0, _name = 0, _score = 0)
{
this.id = _id;
this.name = _name;
this.score = [..._score];
}
//id
getId() {
return this.id;
}
setId(_id) {
this.id = _id;
}
//name
getName() {
return this.name;
}
setName(_name) {
this.name = _name;
}
//score
getScore() {
return this.score;
}
setScore(score ,idx) {
this.score[idx] = score
}
//평균
getAverage() {
let total = 0;
for (let val of this.score)
{
total = total + val;
}
return total/this.score.length;
}
};
const score = [100, 87, 54]
const st1 = new student('JSR', '정상록', score)
//출력
st1.setId('SSS');
st1.setScore(0, 1);
console.log(st1.getId())
console.log(st1.getName())
console.log(st1.getScore())
console.log(st1.getAverage().toFixed(1))
//SSS
//정상록
//(3) [100, 0, 54]
//51.3
</script>
</body>
장점 :
- 접근제어가 용이하다.
- 객체의 선언부와 정의부가 분리된다.
- 다른 언어 객체지향 언어(ex) java)에서 사용하는 구현 스킬을 그대로 사용한다.
- 가독성이 좋다.
단점 :
- 현재로서 단점은 해결이 불가능하다.
결론 : Class는 ES5의 단점을 개선시켰다.
접근제어
private
클래스의 속성이나 메서드를 외부에서 접근할 수 없도록 하는 한정자.
#을 붙여 전방선언 한 뒤 모든 속성에 #을 붙임
이는 변수 명자체가 변경됨을 의미한다. EX) id → #id
<body>
<script>
class cs {
//private 선언
#a;
#b;
constructor(_a, _b) {
this.#a = _a;
this.#b = _b;
}
getA(){
return this.#a
}
getB(){
return this.#b
}
getAdd(){
return this.#a + this.#b
}
}
const result = new cs(10, 9)
console.log(result.getA())
console.log(result.getB())
console.log(result.getAdd())
//10
//9
//19
</script>
</body>
get, set
getter, setter를 위해서 만든 새로운 문법
형식
<body>
<script>
class cs {
#a;
#b;
constructor(_a, _b) {
this.#a = _a;
this.#b = _b;
}
get attribute_name () {
return value;
}
set attribute_name (value) {
}
}
</script>
</body>
예시
<body>
<script>
class cs {
#a;
#b;
constructor(_a, _b) {
this.#a = _a;
this.#b = _b;
}
//get 사용
get Add(){
return this.#a + this.#b
}
get A (){
return this.#a
}
//set 사용
set setA(_a) {
this.#a = _a;
}
}
const result = new cs(10, 9)
result.setA = 7; //set 사용
console.log(result.Add) //get사용
console.log(result.A)
//16
//7
</script>
</body>
반응형
'JavaScript' 카테고리의 다른 글
[JavaScript] 상속(Inheritance), super() (0) | 2022.04.21 |
---|---|
[JavaScript] throw(예외 발생) (0) | 2022.04.21 |
[JavaScript] Constructor 예제 (2) | 2022.04.19 |
[JavaScript] new.target (0) | 2022.04.19 |
[JavaScript] Prototype (0) | 2022.04.19 |