heyday2024 님의 블로그
[JS 문법 5주차(2)] Class -생성, getters & setters 본문
1. Class
Javascript에서 왜 class라는 문법(ES6)이 생겼을까?
다른 여러 프로그래밍 언어(c#, c++, java...)는 대개 클래스 기반 프로그래밍 개발기법을 사용함
(상속, 생성자 등...)
이런 언어들을 사용했던 개발자들이 자바스크립트로 넘어와서 자꾸 클래스 처럼 개발하려고 하다보니까 JS에서도 그 니즈를 반영한 것.
클래스 (Class)
- 클래스는 설계도에 해당하며, 여러 객체를 만들 수 있는 틀.
- 이 설계도에는 객체가 가져야 할 특성(속성)과 행동(메서드)이 정의되어 있음.
- 예를 들어 책상을 만드는 설계도를 보면 어떤 종류의 책상을 만들수 있는지 그리고 그 특징이 무엇인지 알 수 있음. 이런 책상을 만드는 설계도가 클래스임.
인스턴스 (Instance)
- 인스턴스는 클래스를 기반으로 만들어진 실제 객체를 의미.
- 같은 클래스로 만들어진 인스턴스라도 서로 다른 속성 값을 가질 수 있음. 예를 들어, 같은 설계도를 이용해 책상을 만들었지만, 각각 다른 색상을 가진 책상 인스턴스들을 만들 수 있음.
- 즉, 클래스는 하나지만, 여러 개의 인스턴스가 생성될 수 있으며, 각 인스턴스는 클래스에 정의된 특성과 행동을 고유하게 가질 수 있음.
===> Class는 객체를 생성하기 위한 일종의 템플릿이고, Class를 생성하기 위해 'class'라는 키워드를 사용함.
class Person {
// constructor는 이름을 변경할 수 없어요.
constructor(name, age) {
// 이름(name)과 나이(age)가 없으면 사람이 아니죠?
// new라는 키워드를 이용해서 인스턴스를 만들 때, 기본적으로
// 넣어야 하는 값들을 의미해요! :)
// 여기서 말하는 this는 만들어질 인스턴스를 의미한다고 생각해주세요!
this.name = name;
this.age = age;
}
// 다양한 메소드를 아래와 같이 정의할 수 있어요.
// 여기서 this.name으로 내부 값을 접근해야 함을 잊지 마세요! :)
sayHello() {
console.log(
`Hello, my name is ${this.name} and I'm ${this.age} years old.`
);
}
}
const person1 = new Person("Alice", 30);
const person2 = new Person("Bob", 25);
// 만든 객체를 토대로 메서드 호출해보기
person1.sayHello(); // 출력: "Hello, my name is Alice and I am 30 years old."
person2.sayHello(); // 출력: "Hello, my name is Bob and I am 25 years old."
- 위 예시: Person이라는 이름의 Class를 만들었고, 그 클래스는 name, age 속성을 가지며 sayHello라는 메소드를 정의함. new라는 키워드로 Person 클래스의 인스턴스를 생성할 수 있음. 그리고 만들어진 인스턴스들은 sayHello라는 메소드를 호출할 수 있음.
2. Constructor?
Class 의 생성자 함수!!!
생성자 함수는 객체를 생성할 때 호출되며, 객체를 초기화하는 역할을 함.
- 'constructor'라는 키워드를 사용함!!
class Car{
constructor(modelName, modelYear, type, price){
this.modelName = modelName;
this.modelYear = modelYear;
this.type = type;
this.price = price;
}
makeNoise() {
console.log(`${this.modelName}: 빵!!!!`);
}
printModelYear() {
console.log(`the modelYear of ${this.modelName} is ${this.modelYear}`);
}
}
const car1 = new Car("Sorento", 2023, "e", 5000);
const car2 = new Car("SM5", 1999, "g", 3000);
const car3 = new Car("QM6", 2010, "g", 4500);
car1.makeNoise();
car2.makeNoise();
car3.makeNoise();
car1.printModelYear();
car2.printModelYear();
car3.printModelYear();
- 생성자 함수(constructor)는 modelName, modeYear, type, price를 받아 새로운 인스턴스들을 생성함. (this 필수!!)
2. Getter & Setter?
Class에서는 getter와 setter를 사용하여 Class의 속성에 접근 가능!!!
- getter는 속성 값을 반환하는 메소드
- setter는 속성 값을 설정하는 메소드
모든 객체지향 프로그래밍 언어 ---> getters, setters 이용해서 안전하게 인스턴스의 속성에 접근하고 제어 가능.
- setter를 추가함으로서 외부에서 받아오는 값을 검증해서 내부에서 사용할지를 결정할 수 있음. 즉, 인스턴스를 만들기위해 외부로부터 받아오는 값이 valid한지 검증할 수 있게됨!!!
class Rectangle{
constructor(width, height) {
this.width = width;
this.height = height;
}
// width를 위한 getter
get width() {
return this.width;
}
//width를 위한 setter
set width(value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 가로길이는 0보다 커야 합니다!");
return;
}
// 검증 2: value가 숫자가 아니면 오류!
else if (typeof value !== "number") {
console.log("[오류] 가로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this.width = value;
}
//height를 위한 getter
get height() {
return this.height;
}
//height를 위한 setter
set height(value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 세로길이는 0보다 커야 합니다!");
return;
}
// 검증 2: value가 숫자가 아니면 오류!
else if (typeof value !== "number") {
console.log("[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this.height = value;
}
}
//instance 생성
const rec1 = new Rectangle(10, 20);
// const rec2 = new Rectangle(10, 30);
// const rec3 = new Rectangle(15, 20);
// ----> 이런 식으로 직접적인 값 세팅은 보안적으로 위험할 수 있고 검증도 어려움
- set과 get키워드를 사용해서 setters, getters를 다 설정해서 constructor에서 instance만들떄 set, get을 거쳐 외부로 들어온 값을 검증 후 그 값들로 초기화 해주는 코드를 만들었다.
하지만, 오류가 뜬다!!
- 위 코드의 문제점은 무엇일까?
- 맨처음에 new Rectangle에서 10, 20 으로 값을 잘 받아온다.
- 그 후, 생성자 함수(constructor)로 각각의 값이 들어온다.
- this.height = height; 그리고 this.width = width; 에 따라, this.height, this.width에 각각의 값을 set하기 위해 set키워드로 만들어놨던 setter함수들로 이동한다.
- setter에서 들어온 값의 유효성을 다 검증한 뒤, 검증이 성공적으로 완료되면 this.height = value; 그리고 this.width = value; 에 따라, 각각의 값을 set하려고 한다.
- 하지만!!!!!! 이 코드는 결국 constructor에 쓰였던 그 코드부분과 같은 코드로, 각각의 값을 set하기 위해 또 setter들을 거치게 된다.
- 계속 이 과정(set 함수 -> 검증 -> set 함수 -> 검증 .......)이 반복되는 무한루프 현상이 생기고, call stack 입장에서는 이 무한 루프때문에 실행 컨텍스트가 계속 생기게 됨.
- 그래서 Maximum call stack size exceeded라는 오류가 뜬 것임.
그래서 생긴 getters와 setters 쓸 때의 약속:
this에 접근하는 프로퍼티 이름 앞에는 항상 underscore(_) 붙여주기!!
- underscore는 프로그래밍 세계에서 private이라는 의미를 많이 가짐
- 이 인스턴스 내에서만 쓰이기 위한 변수로서 분리하겠다는 뜻.
class Rectangle {
constructor(width, height) {
// underscore : private(은밀하고, 감춰야 할 때)
this._width = width;
this._height = height;
}
// width를 위한 getter
get width() {
return this._width;
}
//width를 위한 setter
set width(value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 가로길이는 0보다 커야 합니다!");
return;
}
// 검증 2: value가 숫자가 아니면 오류!
else if (typeof value !== "number") {
console.log("[오류] 가로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._width = value;
}
//height를 위한 getter
get height() {
return this._height;
}
//height를 위한 setter
set height(value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 세로길이는 0보다 커야 합니다!");
return;
}
// 검증 2: value가 숫자가 아니면 오류!
else if (typeof value !== "number") {
console.log("[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._height = value;
}
getArea() {
console.log("넓이는 ", this._height * this._width);
}
}
//instance 생성
// const rec2 = new Rectangle(10, 30);
// const rec3 = new Rectangle(15, 20);
// ----> 이런 식으로 직접적인 값 세팅은 보안적으로 위험할 수 있고 검증도 어려움
const rec1 = new Rectangle(10, 20);
console.log("높이: ", rec1.height, " 너비:", rec1.width); //높이: 20 너비: 10
rec1.getArea(); //넓이는 200
- 수정된 코드(underscore!!!!!!!!!!!!)
<getters, setters 이용한 예시 코드>
// [요구사항]
// 1. Car라는 새로운 클래스를 만들되, 처음 객체를 만들 때는
// 다음 네 개의 값이 필수로 입력돼야 합니다!
// (1) modelName
// (2) modelYear
// (3) type : 가솔린(g), 전기차(e), 디젤(d)
// (4) price
// 2. makeNoise() 메서드를 만들어 클락션을 출력해주세요.
// 2-1. 해당 자동차가 몇년도 모델인지 출력하는 메서드 작성!
// 3. 이후 자동차를 3개 정도 만들어주세요(객체 생성)
// [추가 요구사항]
// 1. modelName, modelYear, price, type을 가져오는 메서드
// 2. modelName, modelYear, price, type을 세팅하는 메서드
// 3. 만든 인스턴스를 통해서 마지막에 set 해서 get 하는 로직까지
class Car {
constructor(modelName, modelYear, type, price) {
this._modelName = modelName;
this._modelYear = modelYear;
this._type = type;
this._price = price;
}
// getters, setters
get modelName() {
return this._modelName;
}
get modelYear() {
return this._modelYear;
}
get type() {
return this._type;
}
get price() {
return this._price;
}
set modelName(value) {
if (value.length === 0) {
console.log("오류 발생 - 모델명이 입력되지 않았습니다");
return;
} else if (typeof value === "string") {
console.log("오류 발생 - 입력된 모델명이 문자형이 아닙니다!");
return;
}
this._modelName = value;
}
set modelYear(value) {
// 유효성 검사
if (value.length !== 4) {
console.log("[오류] 입력된 년도가 4자리가 아닙니다.확인해주세요!");
return;
} else if (typeof value !== "string") {
console.log("[오류] 입력된 모델명이 문자형이 아닙니다!");
return;
}
this._modelYear = value;
}
set type(value) {
if (value.length <= 0) {
console.log("[오류] 타입이 입력되지 않았습니다. 확인해주세요!");
return;
} else if (value !== "g" && value !== "d" && value !== "e") {
// g(가솔린), d(디젤), e(전기차)가 아닌 경우 오류
console.log("[오류] 입력된 타입이 잘못되었습니다. 확인해주세요!");
return;
}
this._type = value;
}
set price(value) {
if (typeof value !== "number") {
console.log("[오류] 가격으로 입력된 값이 숫자가 아닙니다. 확인해주세요!");
return;
} else if (value < "1000000") {
console.log("[오류] 가격은 100만원보다 작을 수 없습니다. 확인해주세요!");
return;
}
this._price = value;
}
// methods
makeNoise() {
console.log(`${this.modelName}: 빵!!!!`);
}
printModelYear() {
console.log(`the modelYear of ${this.modelName} is ${this.modelYear}`);
}
}
const car1 = new Car("Sorento", 2023, "e", 5000);
const car2 = new Car("SM5", 1999, "g", 3000);
const car3 = new Car("QM6", 2010, "g", 4500);
car1.makeNoise();
car2.makeNoise();
car3.makeNoise();
car1.printModelYear();
car2.printModelYear();
car3.printModelYear();
// getter 예시1
console.log(car1.modelName);
// setter 예시1
car1.modelName = 1;
console.log(car1.modelName);
유효성 검사는 사용자들이 입력한 값에 대한 오류를 잡아내는 데 필수적임으로,
최대한 오류를 일으킬 수 있는 데이터들을 많이 걸러주는 것이 들어오는 데이터 관리를 더욱 편리하고 유용하게 하기 위해 매우 중요하다!!!!!!
'프론트엔드 부트캠프' 카테고리의 다른 글
[JS 문법 5주차(4)] 클로저 (2) | 2024.10.27 |
---|---|
[JS 문법 5주차(3)] 클래스 상속과 정적 메소드 (1) | 2024.10.26 |
[JS 문법 5주차] DOM, DOM_API (3) | 2024.10.24 |
This, Class, Scope (0) | 2024.10.23 |
[4주차 JS 문법(2)] 콜백지옥과 비동기 제어 (0) | 2024.10.22 |