ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JavaScript에서 Priavate 구현
    Javascript 2020. 3. 15. 18:20
    In its current state, there is no "direct” way to create a private variable in JavaScript. 
    -> 현재 상태에서 자바스크립트 private 변수를 (은닉화) 만드는 "직접적인" 방법은 없습니다.
    In other languages, you can use the private keyword or double-underscores and everything works,
    -> 다른 언어에서, private 키워드(자바 등) 또는 __ 이중 underscore 를 사용하는 등의 방법을 사용할 수 있지만
    but variable privacy in JavaScript carries characteristics that make it seem more akin to an emergent trait of the language rather than an intended functionality. 
    -> JavaScript는 의도 된 기능보다는 언어의 특성과 더 유사하게 보이는 특성을 가지고 있습니다.

    * 더욱이 함수 스코프를 가지고 있는 "var"를 사용할 때는 이런 방법이 거의 불가능하다고 봤어도 된다고 봅니다.

    // 글로벌 변수 a 선언
    var a = 123;
    
    // 함수 스코프에 b선언
    (function() {
      console.log(b); // 호이스팅 때문에 undefined 뜹니다.
      var b = 456;
    })();
    
    console.log(a); // => 123
    console.log(b); // 참조 예외 발생 (에러) 
    // b는 함수형 스코프 밖에서 접근할 수 없기 때문입니다.

    * es6의 탄생으로 인해서 블록 범위 스코프인 let과 const가 나오게 됩니다.

    const a = 123;
    
    // 블록스코프 예시1
    if (true) {
      const b = 345;
    }
    
    // 블록스코프 예시2
    {
      const c = 678;
    }
    
    console.log(a); // 123
    console.log(b); // 참조에러 블록스코프 밖에서 내부 변수 참조 불가
    console.log(c); // 참조에러 블록스코프 밖에서 내부 변수 참조 불가

    * 범위를 벗어난 코드는 변수에 액세스 할 수 없기 때문에 프라이버시의 특성을 얻습니다.

    * 여러 가지 방법으로 구현하기위한 몇 가지 기술을 다룰 것입니다.

    * JavaScript의 함수도 블록이므로 모든 가변 키워드가 작동합니다.

    * 또한 "모듈"이라는 매우 유용한 디자인 패턴을 구현할 수 있습니다.

    * 모듈 디자인 패턴은 공용 및 개인 구성 요소를 결합하고 프로그램을 더 작은 구성 요소로 나누고 "캡슐화"라는 프로세스를 통해 프로그램의 다른 부분에 액세스 할 수있는 부분 만 노출시키기 때문에 JavaScript에서 매우 유용합니다.

    * 이 방법을 통해 우리는 사용해야 할 사항 만 공개하고 볼 필요가없는 나머지 구현을 숨길 수 있습니다.

    * 이를 구현하기 위해 함수 범위를 활용할 수 있습니다.

     

    const CarModule = () => {
      let milesDriven = 0;
      let speed = 0;
    
      const accelerate = (amount) => {
        speed += amount;
        milesDriven += speed;
      }
    
      const getMilesDriven = () => milesDriven;
    
      // "return" 키워드를 사용하여 무엇을 노출 시킬 지 숨길 지 결정할 수 있습니다.
      // 이 상황에서는 우리는 유일하게 accelerate() 함수와 getMilesDriven() 함수만을 노출시켜야합니다.
      return {
        accelerate,
        getMilesDriven
      }
    };
    
    const testCarModule = CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());

    이 상황에서 private 변수에 대한 이점이 분명해지기 시작합니다.

    변수, 함수 또는 기타 내부 구성 요소에 액세스하는 기능을 제거하면 의도하지 않은 것을 실수로 다른 사람이 실수로 사용하여 발생하는 오류의 표면적을 줄일 수 있습니다.

     

     

    function CarModule() {
      let milesDriven = 0;
      let speed = 0;
    
      // CarModule을 참조하지않고 this 키워드를 사용합니다.
      this.accelerate = (amount) => {
        speed += amount;
        milesDriven += speed;
      }
    
      this.getMilesDriven = () => milesDriven;
    }
    
    const testCarModule = new CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());

    * es6 CLASS를 사용한 방법

    class CarModule {
      /*
        milesDriven = 0;
        speed = 0;
      */
      constructor() {
        this.milesDriven = 0;
        this.speed = 0;
      }
      accelerate(amount) {
        this.speed += amount;
        this.milesDriven += this.speed;
      }
      getMilesDriven() {
        return this.milesDriven;
      }
    }
    
    const testCarModule = new CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());

     

    * 언더스코어를 사용하는 방법도 있습니다.

    * 밑줄 (_)로 변수 앞에 접두사를 붙이면 여전히 외부에 "표시"되지만 개발자에게 "이 변수를 만지지 마십시오." 라고 해줍니다.

    /*
      _milesDriven = 0;
      _speed = 0;
    */
    constructor() {
      this._milesDriven = 0;
      this._speed = 0;
    }

     

    * 기술적으로, 클래스에서 변수 프라이버시를위한 메소드가 있습니다. 

    class CarModule {
      constructor() {
        let milesDriven = 0;
        let speed = 0;
    
        this.accelerate = (amount) => {
          speed += amount;
          milesDriven += speed;
        }
    
        this.getMilesDriven = () => milesDriven;
      }
    }
    
    const testCarModule = new CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());
    console.log(testCarModule.speed); // undefined

    * weakMap을 사용한 방법도 있습니다.

    class CarModule {
      constructor() {
        this.data = new WeakMap();
        this.data.set(this, {
          milesDriven: 0,
          speed: 0
        });
      }
    
      accelerate(amount) {
        // this keyword 대신에 weakMap을 사용합니다.
        const data = this.data.get(this);
        const speed = data.speed + amount;
        const milesDriven = data.milesDriven + data.speed;
        this.data.set({ speed, milesDriven });
      }
    
      this.getMilesDriven = () => this.data.get(this).milesDriven;
    }
    
    const testCarModule = new CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());
    console.log(testCarModule.data); //=> WeakMap { [items unknown] }

    * 하지만 이 방법은 깊은 복사를 통해 새로운 CarModule을 선언하고 복사할 수 있으므로 실제로는 private이 아닙니다.

    * 이것은 또 심볼을 사용하여 해결할 수 있습니다.

    class CarModule {
      constructor() {
        this.speedKey = Symbol("speedKey");
        this.milesDrivenKey = Symbol("milesDrivenKey");
        this[this.speedKey] = 0;
        this[this.milesDrivenKey] = 0;
      }
    
      accelerate(amount) {
        this[this.speedKey] += amount;
        this[this.milesDrivenKey] += this[this.speedKey];
      }
    
      getMilesDriven() {
        return this[this.milesDrivenKey];
      }
    }
    
    const testCarModule = new CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());
    console.log(testCarModule.speed); // => undefined 
    

    TC39 private class field proposal 라는 새로운 방법이 나왔습니다( 현재는 babel 사용하여 적용해야 함 )

    단순하게 # 만 붙이면 됩니다.

     

    class CarModule {
      #speed = 0
      #milesDriven = 0
      
      accelerate(amount) {
        this.#speed += amount;
        this.#milesDriven += speed;
      }
    
      getMilesDriven() {
        return this.#milesDriven;
      }
    }
    
    const testCarModule = new CarModule();
    testCarModule.accelerate(5);
    testCarModule.accelerate(4);
    console.log(testCarModule.getMilesDriven());
    console.log(testCarModule.speed); //=> undefined

     

     

     

     

    출처 : https://css-tricks.com/implementing-private-variables-in-javascript/

Designed by Tistory.