[자바스크립트]

[JavaScript/DeepDive]25.클래스(2)

ki7348 2021. 5. 31. 10:43
  • [25.6] 클래스의 인스턴스 생성과정
  • new 연산자와 함께 클래스를 호출하면 생성자 함수와 마찬가지로 클래스의 내부 메서드 [[Construct]]가 호출된다.
  • 인스턴스는 다음의 과정을 거쳐 생성된다.
    • 인스턴스 생성과 this 바인딩
      • new 연산자와 함께 클래스를 호출하면 constructor의 내부 코드가 실행되기에 앞서 암묵적으로 빈 객체가 생성된다.
      • 이 빈 객체가 바로 (아직 완성되지는 않았지만) 클래스가 생성한 인스턴스다.
      • 이때 클래스가 생성한 인스턴스의 프로토타입으로 클래스의 prototype 프로퍼티가 가리키는 객체가 설정된다.
      • 그리고 암묵적으로 생성된 빈 객체, 즉 인스턴스는 this에 바인딩된다.
      • 따라서 constructor 내부의 this 클래스가 생성한 인스턴스를 가리킨다.
    • 인스턴스 초기화
      • constructor의 내부 코드가 실행되어 this에 바인딩되어 있는 인스턴스를 초기화한다.
      • 즉, this에 바인딩되어 있는 인스턴스에 프로퍼티를 추가하고 constructor가 인수로 전달받은 초기값으로 인스턴스의 프로퍼티값을 초기화한다.
      • 만약 constructor가 생략되었다면 이 과정도 생략된다.
    • 인스턴스 반환
      • 클래스의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
  • class Person {
         // 생성자
         constructor(name){
              // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.
              console.log(this); // Person { }
              console.log(Object.getPrototypeOf(this) === Person.prototype); // true
         
              // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
              this.name = name;
              // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
         }
    }

 

 

 

  • [25.7] 프로퍼티
  • 인스턴스 프로퍼티
  • 인스턴스 프로퍼티는 constructor 내부에서 정의해야 한다.
  • class Person {
         constructor(name) {
              // 인스턴스 프로퍼티
              this.name= name; // 네임 프로퍼티는 public하다.
         }
    }
    const me = new Person('Lee');
    console.log(me); // Person {name: "Lee"}
    • 인스턴스 프로퍼티는 항상 public하다.
  • 접근자 프로퍼티
  • 접근자 프로퍼티는 자체적으로는 값([[Value]] 내부슬롯)을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티다.
  • 접근자 프로퍼티는 자체적으로는 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수, 즉 getter 함수와 setter 함수로 구성되어 있다.
    • getter 함수는 인스턴스 프로퍼티에 접근할 때마다 프로퍼티 값을 조작하거나 별도의 행위가 필요할 때 사용한다.
    • setter는 인스턴스 프로퍼티에 값을 할당할 때마다 프로퍼티 값을 조작하거나 별도의 행위가 필요할 때 사용한다.
  • 클래스의 메서드는 기본적으로 프로토타입 메서드가 된다.
    • 따라서 접근자 프로퍼티 또한 인스턴스 프로퍼티가 아닌 프로토타입 프로퍼티가 된다.
  • 클래스 필드 정의 제안
  • 클래스 필드(필드 또는 멤버)는 클래스 기반 객체지향 언어에서 클래스가 생성할 인스턴스의 프로퍼티를 가리키는 용어다.
  • 최신 브라우저와 최신 Node.js에서는 다음과 같이 클래스 필드를 클래스 몸체에 정의할 수 있다.
    • class Person {
           // 클래스 필드 정의
           name = 'Lee';
      }
      const me = new Person( );
      console.log(me); // Person {name: "Lee"}
  • 클래스 몸체에서 클래스 필드를 정의하는 경우 this에 클래스 필드를 바인딩해서는 안 된다.
  • 클래스 필드를 참조하는 경우 자바와 같은 클래스 기반 객체지향 언어에서는 this를 생략할 수 있으나 자바스크립트에서는 this를 반드시 사용해야 한다.
  • 인스턴스를 생성할 때 외부의 초기값으로 클래스 필드를 초기화해야 할 필요가 있다면 constructor에서 클래스 필드를 초기화해야 한다.
  • 함수는 일급 객체이므로 함수를 클래스 필드에 할당할 수 있다.
    • 따라서 클래스 필드를 통해 메서드를 정의할 수도 있다.
      • class Person {
             // 클래스 필드에 문자열을 할당
             name = 'Lee';

             // 클래스 필드에 함수를 할당
             getName = function ( ) {
                  return this.name;
             }
             // 화살표 함수로 정의할 수도 있다.
             // getName = ( ) => this.name;
        }

        const me = new Person( );
        console.log(me); // Person {name: "Lee", getName: f}
        console.log(me.getName) // Lee
  • 이처럼 클래스 필드에 함수를 할당하는 경우, 이 함수는 프로토타입 메서드가 아닌 인스턴스 메서드가 된다.
  • 모든 클래스 필드는 인스턴스 프로퍼티가 되기 때문이다.
  • private 필드 정의 제안
  • 자바스크립트는 캡슐화를 완전하게 지원하지 않는다.
    • 인스턴스 프로퍼티는 인스턴스를 통해 클래스 외부에서 언제나 참조할 수 있다.
      • 즉, 언제나 public이다.
        • 클래스 필드 정의 제안을 사용하더라도 클래스 필드는 기본적으로 public하기 때문에 외부에 그대로 노출된다.
  • TC39 프로세스의 stage 3(candidate)에는 private 필드를 정의할 수 있는 새로운 표준 사양이 제안되어 있다.
  • private 필드의 선두에는 #을 붙여준다.
  • private 필드를 참조할 때도 #을 붙어주어야 한다.
    • class Pesron {
           // private 필드 정의
           #name = ' ';

           constructor(name) {
                // private 필드 참조
                this.#name = name;
           }
      }
      const me = new Person('Lee');
      // private 필드 #name은 클래스 외부에서 참조할 수 없다.
      console.log(me.#name);
      // SyntaxError: Private field '#name' must be declared in an enclosing class
      • public 필드는 어디서든 참조할 수 있지만 private 필드는 클래스 내부에서만 참조할 수 있다.
접근 가능성 public private
클래스 내부  O O
자식 클래스 내부 O X
클래스 인스턴스를 통한 접근 O X
  • 이처럼 클래스 외부에서 private 필드에 직접 접근할 수 있는 방법은 없다.
    • 다만 접근자 프로퍼티를 통해 간접적으로 접근하는 방법은 유효하다.
  • private 필드는 constructor가 아닌 반드시 클래스 몸체에 정의해야 한다.