원문 캡처 · bryanpg.com
원문 캡처 · bryanpg.com

직접 제어하지 않는 객체가 실행 중에 어떤 기능을 제공하는지 알아내기는 쉽지 않다. 자바스크립트의 프록시(Proxy)는 속성 접근과 열거를 가로채 객체의 실제 모습과 다른 정보를 보여줄 수 있다.

웹 API를 호출하거나 프로젝트에 라이브러리를 가져오면, 직접 만들지 않은 객체를 다루게 된다. 이 객체의 소스 코드를 보지 않고도 실행 중에 무엇을 할 수 있는지 알아낼 방법이 있을까? 예를 들어 수수께끼 같은 obj를 살펴보자.

처음 보면 호출할 수 있는 속성은 hello 하나뿐인 듯하다. 하지만 obj.goodbye()도 작동한다. goodbye는 console.log에 나타나지 않고, Object.keys(obj), Reflect.ownKeys(obj), for (const key in obj)로 열거해도 찾을 수 없다. 브라우저 개발자 도구에서 조사할 수 있도록 obj를 globalThis에 올려 두었지만, 거기서도 goodbye의 흔적을 찾을 수 없다.

자바스크립트의 프록시는 속성 접근과 대입, 열거, 삭제를 비롯해 객체에서 일어나는 거의 모든 작업을 가로챌 수 있다. 프록시를 훅이나 미들웨어처럼 생각하면 된다. 호출자가 프록시로 감싼 객체를 원하는 모습으로 보게 만들 수 있다. 위 예시처럼 속성을 숨기거나 가상의 속성을 만들고, 속성에 대한 작업이 예상과 다르게 작동하게 할 수도 있다.

프라그마 트와이스(Pragma Twice)는 게임 속 모든 객체에 API가 있는 자바스크립트 퍼즐 어드벤처다. 이 게임을 만들면서 플레이어가 게임을 통해 알아내기 전까지 특정 API 메서드를 숨기고 싶었다. 동시에 그 메서드를 아는 숙련자는 처음부터 사용할 수 있기를 바랐다. 진행하면서 새로 얻는 핵심이 지식이고, 비밀을 알면 여러 지름길을 이용할 수 있다는 점에서 프라그마 트와이스를 Tunic과 비슷하게 만들고 싶었다. 프록시는 이 목적에 잘 맞았다.

프록시는 악의 없는 용도로도 쓸 수 있다. 예를 들어 console.log가 콘솔과 파일에 모두 출력하게 만들고 싶다면, 전역 console을 프록시로 바꿔 호출을 원래 콘솔과 파일 로거 양쪽으로 전달할 수 있다. Vue 같은 반응형 프레임워크도 프록시를 사용해 객체의 변경을 자동으로 감지하고 그에 맞춰 UI를 갱신한다. Vue의 반응성 구현에서 그 사례를 확인할 수 있다.

프록시가 숨긴 속성을 소스 코드 없이 찾아낼 수 있을까? 가능할 수도 있다. 이론적으로는 typeof obj[guess]를 사전 대입이나 무차별 대입과 함께 사용해 속성이 있는지 추론해 볼 수 있다. 개발자 도구로 소스를 보지 않고 시도해 보려면 프라그마 트와이스 웹 데모를 이용할 수 있다. 성공하면 알려 달라.

처음의 hello·goodbye 예시에 사용된 전체 소스 코드도 제공한다고 안내하지만, 이 자료에는 코드가 포함되어 있지 않다.