22.02.24(목) 클로저,클래스

luckygamza·2022년 2월 24일
0

TIL

목록 보기
8/21

클로저

클로저는 함수와 그 함수가 선언된 렉시컬 환경의 조합이다.

일반적인 클로저의 정의

외부 함수보다 내부에 있는 중첩함수가 더 오래 유지되는 경우, 중첩 함수는 외부 함수의 식별자를 참조할 수 있다.
이것이 가능한 이유는, 외부 함수는 끝나서 외부 함수의 실행 컨텍스트는 스택에서 지워졌다 하더라도,
외부 함수의 렉시컬 환경이 내부의 중첩 함수에 의해 참조되고 있으면,
외부 함수의 렉시컬 환경은 가비지 컬렉터에 의해 수집되는 대상이 아니기 때문에 외부 함수의 렉시컬 환경은 살아남아있을 수 있기 때문이다.

일반적으로 이야기하는 클로저는
1) 상위 스코프의 식별자를 참조하고 있고, 2) 외부함수보다 더 오래 유지되고 있는 중첩 함수를 의미한다.

클로저를 사용해서 정보 은닉하기

const Person = function () {
    let _age = 0;
    function Person(name,age) {
        this.name = name;
        _age = age;
    }
    Person.prototype.sayHi = function() {
        console.log(`Hi! I'm ${this.name} and ${_age}.`);
    }
    return Person;
}();
const me = new Person("seyeon",26);
console.log(me.name); //seyeon
console.log(me._age); //undefined
console.log(me.sayHi()); //Hi! I'm seyeon and 26.

위 코드에서 _age는 즉시 실행함수의 렉시컬 환경에 바인딩 된 식별자일 뿐이기에,
생성자 함수로 만들어낸 me 객체에는 포함되어 있지 않다.
따라서 undefined로 표시된다. 이런 방식으로 javascript는 정보 은닉이 가능하다.
이 private한 값에 직접 접근하면 값을 가져올 수 없지만, 간접 접근하면 가져올 수 있다.
me.sayHi()의 실행결과를 보면 _age를 읽어와서 출력해준다.
이유는 즉시 실행 함수의 실행 컨텍스트는 종료되었지만 sayHi라는 중첩 함수에서 _age를 참조하고 있기에 즉시 실행 함수의 렉시컬 환경은 살아있기 때문이다.
이 때의 sayHi 함수는 클로저에 해당한다.

클래스

클래스도 값으로 사용할 수 있는 일급 객체이다.
클래스는 생성자 함수의 또다른 정의 방법이다.
클래스나 생성자 함수나 다 프로토타입 기반의 객체 생성 메커니즘이다.
클래스의 몸체에는 메소드만 정의할 수 있다.

(하지만 클래스필드는 곧 정식으로 도입될 예정이라 MDN 문서에서 볼수 있듯이 모던 브라우저들은 클래스 필드를 정의한 것도 읽을 수 있게 선제적으로 대응해놓았다)

클래스 안에 정의할 수 있는 메소드는

  • constructor
  • 프로토타입 메소드
  • 정적 메소드

이렇게 3가지이다.
(class의 constructor와 prototype 객체의 constructor는 이름만 같을 뿐 다른 것이다. prototype객체의 constructor는 생성자 함수를 가리킨다.)

constructor

인스턴트 프로퍼티는 constructor 내부에서 정의해야 한다.(ex) this.name = name)
constructor는 별도의 반환문을 갖지 않아야 한다. 이유는 new 연산자와 함께 클래스가 호출되면 생성자 함수로 객체를 생성할 때와 마찬가지로 암묵적으로 this를 반환하기 때문이다.

프로토타입 메소드와 정적 메소드의 차이

  1. 정적 메소드와 프로토타입 메소드는 자신이 속해있는 프로토타입 체인이 다르다.
  2. 정적 메소드는 클래스로 호출하고, 프로토타입 메소드는 인스턴스로 호출한다.
  3. 정적 메소드는 인스턴스 프로퍼티를 참조할 수 없지만, 프로토타입 메소드는 인스턴스 프로퍼티를 참조할 수 있다.
  • 3번에 따라서 this를 사용하지 않는 메소드는 정적 메소드로 정의하는 것이 좋다.

인스턴트 프로퍼티를 정의하는 두 가지 방법

  1. constructor에서 정의하고 초기화해주기
  2. 클래스필드로 정의하기 (곧 표준으로 도입될 기능)
  • 클래스 필드를 private으로 만들려면 앞에 #을 붙여주면 된다.(곧 표준으로 도입될 기능)

클래스 상속

클래스는 클래스의 프로토타입만 프로토타입 체이닝이 가능한 게 아니라, 클래스 자체 또한 프로토타입 체이닝이 가능하다.(생성자 함수는 생성자 함수의 프로토타입만 프로토타입 체이닝이 가능하다.)
클래스의 클래스 자체 프로토타입 체인을 이용하면 상속을 구현할 수 있다.
프로토타입 체인을 이용해서 상속을 구현하기 때문에,
extend 키워드 다음에는 [[Construct]] 내부 메소드를 갖는 함수 객체로 평가 될수 있는 모든 표현식이 사용가능하다. 따라서 동적으로 상속 받을 대상을 결정할 수 있다.

class Pet extends (Condition ? Dog : Cat) { // 동적으로 상속받을 대상을 결정하는 서브 클래스
  ...
}

수퍼클래스와 서브클래스의 차이

다른 클래스를 상속자지 않는 클래스(그리고 생성자함수)는 new연산자와 함께 호출되었을 때, 암묵적으로 빈 객체, 즉 인스턴스를 생성하고 이를 this에 바인딩한다.
하지만, 서브클래스는 자신이 직접 인스턴스를 생성하지 않고, 수퍼클래스에게 인스턴스 생성을 위임한다.
이것이 서브클래스의 constructor에서 반드시 super를 호출해야 하는 이유다.
서브클래스는 별도의 인스턴스를 생성하지 않고, super가 반환한 인스턴스를 this에 바인딩하여 그대로 사용한다.

0개의 댓글

관련 채용 정보