[JS] 클래스 상속 / 클로저

자식 클래스가 생성자를 오버라이딩 하는 경우

자식 클래스의 생성자가 호출됐을 때 무조건 부모 클래스의 생성자도 호출된다. 그런데, 자식클래스가 생성자를 오버라이딩 하는 경우가 생긴다.

class Car {
  constructor (name, type, price) {
    this._name = name;
    // ...생략
  }
}

class ElectronicCar {
  constructor (name, price, chargeTime) {
    super(name, 'e', price);
    this._chargeTime = chargeTime;
  }
  
  set chargeTime(value) {
    this._chargeTime = value;
  }
}

const elecCar = new ElectronicCar("차 이름", 9000);

예를들어 이와같이 Car를 상속받은 ElectronicCar는 타입을 굳이 생성자에 넣어줄 필요는 없다. 하지만 자동으로 부모 클래스의 상속자가 호출될 때는 타입의 정보가 필요하기 때문에 이 값들로 초기화하면 된다고 값을 보내줘야 한다!

부모클래스의 생성자를 호출한 뒤 부모 클래스에선 필요하지 않던 값을 이 객체의 값으로 초기화 시켜준다.

만약 getter, setter를 사용하는 경우 this._(변수명)을 통해 접근하는 것을 잊지말자~

 

 

클로저 (Closure)

클로저란?

함수와 그 함수가 선언된 렉시컬 환경과의 조합

외부함수보다 중첩함수가 더 오래 유지되는 경우, 중첩합수는 생명주기가 끝난 외부함수의 변수를 여전히 참조할 수 있다.

이때의 중첩함수를 클로저라고 한다!

 

렉시컬 환경

const x = 1;

function outerFunc() {
  const x = 10;
  innerFunc();
  
  function innerFunc() {
    console.log(x);
  }
}

outerFunc();

위의 경우 innerFunc()의 x는 어떤 값을 참조하는걸까?

innerFunc()의 스코프에 x가 없기때문에 outer인 outerFunc의 x = 10을 참조한다.

호출된 당시의 환경 X, 함수가 선언된 당시의 환경 (=== 렉시컬 환경)!

 

const x = 1;

function outerFunc() {
  const x = 10;
  innerFunc();
}

function innerFunc() {
  console.log(x);
}

outerFunc();

 

위의 경우 1이 출력된다. 마찬가지로 innerFunc를 호출한 위치와 상관없이 선언했을 때의 외부환경을 참조하고 있기 때문!! 

 

const x = 1;

function outer() {
  const x = 10;
  const inner = function() {
    console.log(x);
  };
  
  return inner;
}

const innerFunc = outer();
// inner를 반환하고 outer의 실행컨텍스트 종료!
innerFunc();

마지막 부분에서 innerFunc()를 호출했을 때 inner가 참조하고있는 선언 당시 outer 환경은 이미 소멸되고 없다.

하지만 innerFunc() 를 호출하면 출력되는 x는 outer의 10이다!

이게 클로저 개념이다.

 

가비지컬렉터

이게 가능한 이유는 가비지컬렉터가 가비지를 정리할 때 아직 사용중인 값은 정리하지 않기 때문이다.

outer의 x를 사용하는 inner가 아직 소멸되지 않고 남아있으므로 정리되지 않고 남아있다!

 

 

클로저의 활용

클로저는 주로 상태를 안전하게 변경하고 유지하기 위해 사용한다!

 

예시

let num = 0;

const increase = function() {
  return num++;
};

console.log(increase());  // 1
num = 100;
console.log(increase());  // 101
console.log(increase());  // 102

보완해야할 사항

- num 값은 increase 호출 전까지 변동되면 안된다.

 

const increase = (function () => {
  let num = 0;
  
  return function() {
    return num++;
  };
})();

console.log(increase());  // 1
console.log(increase());  // 2
console.log(increase());  // 3

위 코드의 실행 단계

1) increase()를 선언하며 즉시실행함수 호출

- 함수가 반환되어 increase에 할당됨

- 즉시실행함수는 소멸됨!

2) increase에 할당됨 함수는 자신이 선언된 당시의 렉시컬 환경을 기억하는 클로저 (num = 0)

3) num은 무조건 increase를 통해서만 접근할 수 있기 때문에 은닉된 정보를 관리할 수있음