ECMAScript | TypeScript

ESCMAScript, Proxy와 Proxy Handler

partner_jun 2017. 9. 11. 09:36

프록시 패턴은 실제 데이터에 접근할 수 있는 일종의 인터페이스(상속구조의 인터페이스가 아니다)를 만드는 디자인 패턴이다. 

자바의 ORM인 JPA에서의 예를 들자면, FetchType.LAZY로 설정되어 있을 때, 어떤 엔티티 객체와 이어진 엔티티 프로퍼티는 '진짜' 객체가 아닌 임시 객체로 실제로 사용될 때 데이터베이스에서 값을 조회해 '진짜' 객체가 만들어진다. 


ES6의 프록시는 JPA의 프록시와는 약간 다른 특성을 가진다. ES6의 프록시는 실제 객체와 핸들러 객체를 이용해 프로퍼티가 추가, 삭제, 변경 혹은 실행 될 때 특정 함수를 실행하는 객체를 만드는 클래스다.


class Person {
constructor(name) {
this.name = name;
}
}
const jack = new Person('JACK');

Person 클래스와 jack 객체 생성



const objHandler = { // 프록시 핸들러 객체
set : function (target, property, value, receiver) { // 대상 오브젝트 프로퍼티가 설정될 때
target[property] = `"proxy set ${value}"`;
return true;
},
get : function (target, property, receiver) { // 대상 오브젝트의 프로퍼티를 얻어올 때
return `"proxy get ${target[property]}"`;
}
};

프록시 객체의 프로퍼티의 핸들러 객체

이 코드에서는 값이 설정될 때와 값을 가져올 때 값을 변경하도록 했다.



let objProxy = new Proxy(jack, objHandler); // 핸들러가 적용된 프록시 객체
objProxy.name = 'JOHN';

console.log(objProxy.name); // "proxy get "proxy set jack""
console.log(objProxy instanceof Person); // true

기반이 되는 객체와 핸들러 객체로 프록시 객체를 만들고 실행한 모습



위 코드는 간단한 핸들러 객체를 만들어 객체 프로퍼티의 값이 set / get 되었을 때 문자열을 추가하도록 구성했다. 간단한 예제 코드지만 ES6 프록시의 특성을 한눈에 파악할 수 있을 것이다. 핸들러 객체가 가로챌 수 있는 'trap'의 목록은 아래와 같다.


 Handler method

Object method 

 getPrototypeOf

 Object.getPrototypeOf()

 setPrototypeOf

 Object.setPrototypeOf() 

 isExtensible

 Object.isExtensible() 

 preventExtensions 

 Object.preventExtensions() 

 getOwnPropertyDescriptor 

 Object.getOwnPropertyDescriptor() 

 defineProperty 

 Object.defineProperty() 

 has 

 Object.has() 

 get

 Object.get()

 set

 Object.set()

 ownKeys

 Object.ownKeys()

 apply

 Object.apply()

 construct

 Object.construct()


trap의 목록에서 알 수 있듯 Proxy 클래스는 Object의 기본 메소드들을 오버라이딩한다.


더 자세한 정보와 다른 트랩을 사용한 예제를 보려면 모질라 제단 홈페이지를 참고하자.