brunch

You can make anything
by writing

C.S.Lewis

by 한상훈 Feb 01. 2022

[고급 자바스크립트]  프록시 객체 사용법

값의 적합성 확인 및 데이터 변경에 따른 기록을 위한 객체

프록시란 무엇인가?

ES6의 프록시(Proxy)는 객체의 변화를 감지해 특정 동작의 트랩(trap)을 설정할 때 사용할 수 있습니다. 데이터 검증에 사용하는 Validator로 사용할 수도 있고, 데이터 변화를 감지하는 로거(logger)로도 사용할 수 있습니다.



위의 코드를 보면 프록시는 2개의 매개변수를 사용합니다. 첫 번째는 프록시에 사용할 대상 객체이고 두 번째 매개변수는 핸들러로 setter와 getter 프로퍼티 및 핸들러 함수(또는 트랩)를 설정할 수 있습니다. 위의 코드에서 보면 프로퍼티에 값을 할당하는 과정(set 발생)이 발생할 때마다 위의 프록시 함수(propValidator)에 있는 setter 함수가 실행되며 값을 검증하게 됩니다.


저는 코드에서 name이라는 프로퍼티에 대해서 값을 검증하고 있는데 타입 에러와 레인지 에러를 검증합니다. 검증 과정에서 허용되지 않은 값이 들어오는 경우 에러를 리턴해 함수를 구성했습니다. 프록시의 매개변수에 대해 좀 더 살펴보면 다음과 같이 설명합니다. (프록시에 대한 MDN 문서)

프록시 MDN 문서 중 일부


프록시 객체에서 핸들러 부분을 잘 활용하면 원하지 않은 데이터가 들어왔을 때 검증 후 에러를 리턴할 뿐 아니라 데이터를 대체하는 용도로도 활용될 수 있습니다. 예를 들면 에러가 될 수 있는 특수문자나 파싱 과정에서 필요 없는 HTML 문자열 등을 제거하는 것도 가능할 것입니다.




프록시 활용하기

프록시를 제대로 활용하기 위해서는 어떤 트랩이 있는지 알고, 활용하는 연습이 필요합니다.


1) get 메서드

프로퍼티가 존재하지 않는(undefined)경우일 때는 "한상훈"이라는 제 이름이 나오고, 값이 존재할 때는 값을 리턴(target[prop])하는 코드입니다. 이 짧은 코드는 활용도가 다양합니다. 자바스크립트를 사용하다보면 값이 존재하지 않는 경우에 참조 에러가 발생하는 경우가 있습니다.


객체가 아닌 값(c)에 대해 선언되지 않은 프로퍼티(a)에 접근하려고 할 때 에러가 발생하는데, 에러가 캐칭되지 않는 경우 프론트와 백엔드 모든 분야에서 시스템이 멈추는 현상을 야기합니다. 하지만 위의 코드를 프록시를 사용해 감싸준다면, 존재하지 않는 프로퍼티에 대해 default값으로 설정한 "한상훈"이라는 문자열이 리턴되므로 에러로 인해 시스템이 멈추는 현상을 막을 수 있습니다.


2) has 메서드

이번엔 객체의 Private 프로퍼티를 감춰보도록 하겠습니다. 자바스크립트의 컨벤션(convention) 중 하나는 외부의 접근을 제한할 필요가 있는 변수 또는 프로퍼티에 대해 언더바(_)로 네이밍을 합니다. 아래의 코드는 언더바로 시작되는 프로퍼티에 대해서 존재하는지 검사할 때 언제나 false를 리턴하는 프록시 코드입니다.

출처: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/has


위의 코드에서 monster1이라는 객체에 할당된 _secret이라는 값은 존재하는지 프록시 없이 검사해보면 true를 리턴합니다.(마지막줄 콘솔로그) 반면 프록시를 사용해 monster1를 감싸주면 해당 프로퍼티의 존재 유무를 false로 리턴하여 외부의 요청에 대해 감출 수 있습니다. 데이터를 내부 로직에서만 사용하고, 외부에서 엑세스는 제한해야하는 경우에는 이와 같이 has를 사용해 값의 존재 유무를 감춰줄 수 있습니다.


3) set 메서드

앞선 아이디어를 조금 더 발전하면 특정 객체의 값이 존재하는지 확인을 막는 것 뿐만 아니라 재할당을 못하도록 제한할 수 있습니다.



위의 코드를 보면 언더바(_)로 시작하는 프로퍼티에 대해 할당이 이뤄질 때 값의 변화 없이 return으로 빠져나가 아무 일도 발생하지 않도록 처리하고 있습니다. 이렇게 set 메서드를 활용하면 값이 차후에 변경되어 문제가 발생하는 것을 막을 수 있습니다. 여기서 조금 더 나아가면 접근 불가능한 프로퍼티에 대해서는 에러를 리턴하도록 하는 처리도 가능할 것입니다.


4) isExtensible 메서드

앞선 코드에서는 값의 재할당을 방어하는 프록시 사용법을 살펴봤다면 객체의 확장(extend)을 막는 것도 알아봅시다.

위의 코드는 자바스크립트를 사용해 npm에 올릴 라이브러리를 제작해보신 적이 없으시면 거의 보기 힘든 메서드가 나옵니다. 바로 Object.preventExtensions입니다. 간단하게 객체의 확장을 방지하는 메서드입니다.


개발자들이 프로젝트를 진행할 때 사용하는 라이브러리나 유틸리티 함수들은 사용 과정에서 드물게  의도하진 않았지만 프로퍼티와 값을 할당하여 사용하는 경우도 생기곤 합니다. 이러한 휴먼에러를 막기 위해서 확장을 할 필요가 없는 객체에 대해서 확장을 막아주는 코드를 사용할 수 있는데, 위의 코드는 이 변화를 감지하는 예입니다.


위의 코드는 MDN에 있는 흔한 예제이지만 초보자 분들에게는 Reflect라는 게 무엇인지도 헷갈리실 것 같습니다. Reflect는 타겟 객체의 상태를 불린으로 리턴하는 여러 메서드를 가진 자바스크립트 기본 객체라고 보시면 됩니다.


https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Reflect


Reflect의 처리기(메서드)가 프록시와 연동됩니다. Reflect의 메서드를 통해 검증하는 값은 프록시에서도 핸들러에 할당하여 처리할 수 있고, 이에 대한 불린 값은 Reflect를 통해 얻을 수 있습니다.


5) apply 메서드

apply는 객체가 함수일 때 사용하면 좋은 메서드입니다. 프록시에 apply를 사용하면 함수가 호출될 때마다 로그를 찍거나 우리가 원하는 어떠한 사전 동작도 코드상으로 구현해 둘 수 있습니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/apply

p라는 프록시 객체는 빈 함수를 타겟으로 가지고 있습니다. p를 호출하게 되면 프록시에 할당된 콘솔로그 코드 및 리턴문이 실행되고 이후에 console.log 값이 호출되는 것을 볼 수 있습니다.


여기까지 따라오셨다면 프록시 객체를 하나의 유틸리티 함수로 만들어 사용하여 함수 전처리에 사용하거나 또는 객체를 보호하거나 확장하거나, 에러 캐칭을 하거나 예상치 못한 에러로 방어하는 아이디어를 떠올리실 수 있을 겁니다. 프록시는 코드의 완성도를 높히고, 검증, 보호, getter, setter 모두 활용될 수 있는 아이디어입니다. 꼭 활용해보세요.

매거진의 이전글 개발자가 자주 보면 좋은 사이트
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari