• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    해결됨

2021.3 현시점에서 'ES202X' 기준으로 private 필드를 일반적으로 어떻게 구현하나요?

21.03.04 18:16 작성 조회수 340

1

  1. ES최신 에서는 class private 키워드 대신 #member 로 private 지정을 하라고 나온것 같은데 어느분은 #을 사용하지 말라고도 하구요, 어떤분은 OLOO 패턴으로 모듈 안에 심볼 사용을 권고하는데 이에 대한 강사님의의견이 궁금합니다
  2. #을 사용 안하신다면 현시점에서는 private 맴버 선언에 여전히 Symbol 을 사용할수 밖에 없는지 궁금합니다.(심볼 사용만이 private 맴버 선언의 유일한 방법인지가 궁금합니다)

읽어주셔서 감사합니다!

답변 2

·

답변을 작성해보세요.

3

#을 사용하지 말 것을 권하는 분들의 이유야 여러가지 있을 수 있겠지만
추측하기로는 다음 몇가지 정도가 아닐까 합니다.

1. 해당 기능 지원이 아직까지 되지 않는 브라우저가 꽤 있다.

https://caniuse.com/mdn-javascript_classes_private_class_fields

>> 현재 실무에서 ES20XX를 쓰는 상태에서 babel 등의 compile을 거치지 않는 경우가 별로 없기 때문에 크게 중요하지 않습니다. 다만 compile을 거치면 어떤 결과가 되는지가 관건일 수는 있습니다.

class A {
    #a = 1;
    getA() { return this.#a; }
}


// babel transpiled ->>

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }

var _a = new WeakMap();
var A = function () {
  function A() {
    _classCallCheck(this, A);
    _a.set(this, {
      writable: true,
      value: 1
    });
  }
  _createClass(A, [{
    key: "getA",
    value: function getA() {
      return _classPrivateFieldGet(this, _a);
    }
  }]);
  return A;
}();

내용을 살펴보면 전역 WeakMap에 private member를 set하고 매번 꺼내어 쓰고 있습니다.
즉 babel을 이용한 방법이 제가 강의에서 소개드린(Symbol의 다음 챕터에서 등장합니다) WeakMap을 이용한 방법과 동일함을 알 수 있죠.

Symbol을 활용하는 방법과 WeakMap을 활용하는 방법의 차이점에 대해서는 강의를 WeakMap까지 들어보시면 어느정도 감을 잡으실 수 있으리라 생각합니다. 일반적으로는 Symbol 정도로도 충분합니다.

2. console 상에서는 여전히 private member가 노출된다.

>>  console.log로 출력해보면 private member가 출력되긴 하지만 접근은 불가능합니다. Symbol을 사용한 경우에도 역시 확인할 수는 있으나 Reflect.ownKeys와 같은 우회를 통해서만 접근할 수 있습니다. 따라서 이런 맥락에서의 비판은 큰 의미가 없다고 생각합니다.

3. 나아가 OLOO가 더 낫다는 주장에 대해서도...

>> 카일 심슨은 ES6 클래스의 '미흡한 부분'을 지적하면서 '기존 기능'인 Object.create, Object.setPrototypeOf 등을 활용하는 편이 더 낫다는 주장을 하는 것으로 알고 있습니다.

일개 직장인에 불과한 보잘 것 없는 제가 감히 견해를 말씀드리자면, 그러한 주장이 일견 타당한 측면이 있긴 하더라도, 그럼에도 불구하고 class의 장점이 퇴색되는 것은 아닙니다. javascript의 미흡한 부분들은 TC39가 매 년 업데이트를 통해 보완하고 있고, 점차 다른 언어의 스펙과 비슷해져 가고 있습니다. 애당초 class는 타 언어 개발자들의 접근성을 높이기 위해 도입되었고 따라서 prototype을 모르더라도 사용할 수 있도록 고안한 것이므로, 지금에 와서 prototype을 직접 사용하는 것은 전혀 권장할 만한 사항이 아니라고 생각합니다.

나아가 카일 심슨의 주장 중 일부는 저로서는 납득하기가 어렵습니다. 예를 들어 "super가 정적 바인딩된다는 점이 문제"라고 하는데, class의 상속관계를 생각해볼 때 이는 당연한 것입니다. 괜히 프로토타입 프로퍼티를 다른 객체에 할당해놓고는 super가 예상과 다르다고 주장하는데, 애초에 그런 행위를 하지 않으면 될 일입니다. 왜 굳이 클래스 안에 있는 메서드를 다른 객체에 할당하려 하는지 모르겠습니다 (...)

각설하고, 일개 개발자인 우리들은 그저 class의 기능이 좀 더 보완되기를 기대하면서 그와 동시에 사용에 익숙해지는 것이 먼저이고, 그 근간에 있는 prototype을 정확히 이해하는 것으로 충분하다고 봅니다. 다양한 의견은 그냥 저런 의견들도 있구나- 하는 정도로 주워담고 넘어가는게 이롭지 않을까 해요 :)

0

Truestar님의 프로필

Truestar

질문자

2021.03.05

답변해주신 구절구절마다 개념을 잡는데 도움이 많이 되었습니다!!
해주신 답변을 통해 시간을 허비할수 있는 부분을 바로 잡을 수 있었습니다.

저도 OLOO 를 처음 접할때, class 사용을 반하는 의견이라 의구심을 품고 있었어요.
강의 예제로도 활용되는건 올바르지 않은 예를 들기 위해 든 것이라고 생각해도 되겠죠?
OLOO 에에 대한 의견이 분분 할 수있는 것인지 처음알게 되었습니다.

두서없는 질문에 양질의 답변을 주셔서 감사드립니다.