본문 바로가기
Javascript

프록시란 무엇일까?

by F.E.D 2022. 10. 3.

Javascript에서 Proxy를 다루는 내용들이 있습니다.

Proxy란 무엇이고 어떻게 사용해야 할까요?

ECMAScript 6에서 정의되어진 Proxies에 대해서 알아보고 사용법을 익혀보는 시간을 가져 보시죠 : )

프록시란 무엇일까

MDN의 문서의 내용과 같이 프록시 객체는 다른 객체에 대한 프록시를 만들고, 이 객체는 해당 객체에 대한 기본 작업을 가로채고 재정의할 수 있는 작업들을 할 수 있다는 것입니다.

다시말하면, 그 객체는 해당 객체를 래핑하고, 그 객체를 재정의하고 사용할 수 있는 것입니다.

일반적으로, 이러한 작업들을 우리는 객체를 가져와서 숨겨진 게이트웨이를 생성하고 원하는 객체에 대한 모든 액세스를 제어할 수 있도록 프록시로 포장한다는 것을 의미합니다.

 

프록시는 두개의 파라미터로 만들어집니다.

  • target : 감싸고 싶은 원본 객체
  • handler : 가로채는 작업을 재정의하는 방법을 정의하는 메서드
const target = {
  name: "noel",
  region: "incheon"
};

const handler = {};

const proxy = new Proxy(target, handler);

프록시는 대부분의 브라우저에서 지원되고, 지원하지 않는 오래된 브라우저들은 폴리필로 대체 가능합니다.

프록시 사용법

만약에 A 편의점에 포켓몬 빵의 재고가 변경될 때마다 알림을 받고 싶습니다.

그러면 프록시를 사용해서 어떻게 할 수 있을까요?

const convenientStore = {
  count: 10,
  name: '포켓몬 빵'
};

const handler = {
   get: function(target, prop, receiver) {
    if (prop === 'count') {
	console.log(`현재 ${target.name}의 개수 : ${target.count} 개`);
    }
    return target[prop];
  }
};

const wrappedConvenientStore = new Proxy(convenientStore, handler);
wrappedConvenientStore.count;

// 결과
// 현재 포켓몬 빵의 개수 : 10 개
// 10

위의 예시로부터 우리는 handler를 통해서 포켓몬 빵의 count에 접근했을 때 현재 포켓몬 빵의 개수가 10개라는 것을 알 수 있었습니다.

 

다음 예시는 3개의 파라미터를 받습니다.

우리는 위의 A 편의점에서 누군가가 포켓몬 빵을 사갔을 때 알림을 받기를 원합니다. 

그리고 또 다른 제약사항으로 편의점은 포켓몬 빵이 0개 미만으로는 내려갈 수 없다는 것 입니다.

이를 위해서 handler/trap을 사용하겠습니다.

 

const convenientStore = {
  count: 10,
  name: '포켓몬 빵'
};

const handler = {
   set: function(obj, prop, value) {
   console.log(`현재 ${obj.name}의 개수 : ${obj.count} 개`);
   if (value < 0) {
       console.log(`포켓몬 빵은 0개 미만이 될 수 없습니다`);
       return false;
   }
   obj[prop] = value;
   return true;
  }
};

const wrappedConvenientStore = new Proxy(convenientStore, handler);

wrappedConvenientStore.count -= 5;
console.log(wrappedConvenientStore.count);

wrappedConvenientStore.count -= 25;
console.log(wrappedConvenientStore.count);

// 현재 포켓몬 빵의 개수 : 10 개
// 5
// 현재 포켓몬 빵의 개수 : 5 개
// 포켓몬 빵은 0개 미만이 될 수 없습니다
// 5

위와 같이 더 이상 감소할 수 없다면 return false를 통해서 작업을 중단할 수 있습니다.

프록시를 사용하고 있는 기술들

많은 기술들이 Proxies를 사용하고 있습니다.

Mobx라던지, Vue, Immer와 같은 상태관리 라이브러리 등이 사용중입니다.

변화가 감지되어 반영되게 만들어야하는 양방향 바인딩을 위한 상태 감지 등 가로채고 재정의하는 모든 메서드에서 사용됩니다.

예시

위에서 사용했듯이 로그로도 사용할 수 있고, 유효성 검사로도 작용할 수 있을 것 같네요.

캐싱적용

캐싱 적용을 해봅니다.

const convenientStore = {
  count: 10,
  name: '포켓몬 빵',
  get price() {
      console.log('빵의 가격');
      return this.count * 1000;
  }
};

let cache = {
    currentCount: null,
    currentValue: null
}

const handler = {
    get: function(obj, prop) {
        if (prop === 'price') {
            let value = cache.currentCount !== obj.count ? obj[prop] : cache.currentValue;
            cache.currentValue = value;
            cache.currentCount = obj.count;        
            return value;
        }
        return obj[prop];
    }
};

const wrappedConvenientStore = new Proxy(convenientStore, handler);

console.log(wrappedConvenientStore.price);
console.log(wrappedConvenientStore.price);
console.log(wrappedConvenientStore.price);
console.log(wrappedConvenientStore.price);

// 빵의 가격
// 10000
// 10000
// 10000
// 10000

DOM 조작

상태가 변경될 때마다 화면의 값들을 업데이트 하고 싶습니다.

set operator/trap을 사용해서 해봅니다.

const convenientStore = {
  count: 10,
  name: '포켓몬 빵',
  get text() {
      return `${this.name}의 개수는 ${this.count}개 입니다.`;
  }
};

const domManipulate = (object, domId) => {
    const handler = {
        set: function(obj, prop, value) {
            obj[prop] = value;
            document.getElementById(domId).innerHTML = obj.text;
            return true;
        }
    };
    return new Proxy(object, handler);
}

const wrappedConvenientStore = domManipulate(convenientStore, "domId");

wrappedConvenientStore.count = 300;
wrappedConvenientStore.count = 500;

See the Pen Proxy by YoungMinKim (@oinochoe) on CodePen.

Proxy에 대해서 알아가는 시간이 되셨기를 바랍니다 : )

 

 

출처 : https://levelup.gitconnected.com/the-amazing-power-of-javascript-proxies-aa27c6d06bcb

댓글