new Class (a, b, c)
처럼 만들어진 property
는
getters
와 setters
를 제공해준다는 것입니다.
js
역시 이런 개념이 있는데
직접 할당하고 세팅하는 방법이 있지만
getter
와 setters
로 가져와서 할당하고 안전하게 세팅하는 방법도 있다.
근데 5-4
의 방식은 개념적으로 부족하다
외부에서 사용도 해야되고 세팅도 할 수 있어야 하는데
class Rectangle {
constructor (height, width) {
this.height = height;
this.width = width;
}
}
위처럼 constructor(height,width)
가 직접 세팅이다.
직접적으로 세팅하는건 -> 내부적인 변수이기 때문에
위험하고 검증도 어렵다.
width를 위한 getter
get width () {}
width를 위한 setter
set width (value) {}
이런 식인데 setter
의 장점은 예를들어
음수가 들어오거나 이상한 값이 들어 왔을 때
대처할 수 있는 역할이 setter
로 세팅하는 방법
- 타입 비교할 때
number
를 생으로 사용해서 비교하면 함수로 인식해서
'number' 문자열로 타입을 비교해야합니다.
무한루프 현상 예시
set height (value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log('[오류] 세로길이는 0보다 커야 합니다!');
return
} else if (typeof value !== 'number') {
console.log('[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다.');
return
}
this.height = value;
}
여기서 set
검증을 하고 this.height
에 20이라는 값을 세팅하는데
근데 다시 set
하기 위해서는 다시 set height
으로 와야된다
48줄로 오면 다시 또 set
해서 38줄로 가고 38줄 ~ 48줄을 계속해서 도니까
실행 컨텍스트의 사이즈가 계속 커지면 나오는 오류가?
Maximum call stack size exceeded
가 나온다.
이 오류를 해결하려면 this.height
이 아닌
this._height
으로 this.
앞에 붙는 모든 인스턴스 값에
underscore === _
를 붙여줘야 한다
언더스코어의 뜻은 : private(은밀하고, 감춰야 할 때라고 가리킨다.)
이 부분은 짧게 넘어가서 나아중에 다시 보게되면
정리를 해볼 생각이다.
class Dog extends Animal {}
상속받을 땐 extends
가 꼭 붙어야 하고
좌에서 우로 읽기 때문에 좌가 자식 우가 부모
class ElectronicCar extends Car {
constructor(modelName, modelYear, price) {
// Car(부모 class)에게도 알려주기!!
super(modelName,modelYear,'e',price);
}
}
여기서 super
라는 키워드가 등장했는데
전기차는 type
이 e
가 고정이지만
부모는 type
을 받아서 서로 다르기 때문에
부모랑 자식의 싱크가 다르기 때문에 맞춰주려고 super
로 사용한다.
constructor(modelName, modelYear, price, chargeTime) {
// Car(부모 class)에게도 알려주기!!
super(modelName,modelYear,'e',price);
this._chargeTime = chargeTime;
}
이런식으로 새로운 속성을 추가할 때는
추가 후 this._charTime = chargeTime
으로 재지명 해주면 된다.
(_ 가 붙은 이유는 아래 get set
을 사용했기 때문에)
// Static Method(= 정적 메소드)
// Class -> 객체를 만들기 위해서 사용하죠!!
// 다량으로, 안전하고, 정확하게
class Calculator {
static add (a, b) {
console.log('[계산기] 더하기를 진행합니다.');
return a + b;
}
static substract(a, b) {
console.log('[계산기] 빼기를 진행합니다.');
return a - b;
}
}
console.log(Calculator.add(3, 5)); // 8
console.log(Calculator.substract(3,5)); // -2
cunstructor
없이도 static
으로 저장해서 바로 사용이 가능하다.
즉 인스턴스 없이도 직접 호출이 가능하다.
(특히 복제할 필요가 없는 데이터를 만들 때 사용되곤 한다.)
const x = 1;
function outerFunc() {
const x = 10;
function innerFunc() {
// x는 어디서 참조할까요 ?????
console.log(x); // 10...!!
}
innerFunc();
}
outerFunc();
렉시컬 환경이란 이런 상황에서 말한다.
먼저 const x = 1;
가 실행되어 실행 컨텍스트에 쌓이고
두번 째로 outerFunc()
가 실행되어
다시 const x = 10;
을 읽고,
그런 다음 아래에 innerFunc();
가 실행되면서
console.log(x)
를 찍는데 여기서 x의 값은 10인 이유가
x를 찾기위해 먼저 innerFunc
를 찾아보고 그 다음 outerFunc
를 찾는다
그렇기 때문에 x는 10이 나오게 된다 읽는 순서 실행 컨텍스트를 기억해야 한다.
[렉시컬 스코프]
JS 엔진은 함수를 어디서 '호출' 했는지가 아니라
어디에 '정의' 했는지에 따라서 스코프(상위 스코프)를 결정한다.
'외부 렉시컬 환경에 대한 참조값' => outer
함수 정의가 평가되는 시점!!!
const x = 1;
// outerFunc내에 innerFunc가
// '호출' 되고 있음에도 불구하고
function outerFunc() {
const x = 10;
innerFunc(); // 1
}
// innerFunc와, outerFunc는 서로
// 다른 scope를 가지고 있다!!!!!
function innerFunc() {
console.log(x); // 1
}
outerFunc();
클로저와 렉시컬 환경은 어떤 관계가 있나?
외부 함수보다 중첩 함수가 더 오래 유지되는 경우,
중첩 함수는 생명 주기가 종료한 외부 함수의 변수를 여전히
참조한다.
이 개념에서 중첩 함수가 바로 클로저다.
클로저가 되는 이유
가비지 컬렉터가 굉장히 똑똑하기 때문에
안쓴다는 기준을 판단할 때 여전히 함수가 참고하고 있다면
그 친구는 놔두는 것이다.
그냥 중첩된 함수에서 외부함수가 종료되었는데도 참조하고 있다.
클로저로 짜여진 기능을 이해는 해야 한다.
클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다.
상태를 안전하게 은닉한다(특정 함수에게만 상태 변경을 허용한다.)