Proxy
는 특정 객체를 감싸 프로퍼티 읽기, 쓰기와 같은 객체에 가해지는 작업을 중간에서 가로채는 객체다.
가로채진 작업은
Proxy
자체에서 처리되기도 하고, 원래 객체가 처리하도록 그대로 전달되기도 한다.
let proxy = new Proxy(target, handler)
인자 설명
target
– 감싸게 될 객체. 함수를 포함한 모든 객체가 가능.
handler
– 동작을 가로채는 메서드인 '트랩(trap)'이 담긴 객체로, 여기서 proxy
를 설정.
let target = {};
let proxy = new Proxy(target, {}); // 빈 핸들러
proxy.test = 5; // 프락시에 값을 씁니다. -- (1)
alert(target.test); // 5, target에 새로운 프로퍼티가 생겼네요!
alert(proxy.test); // 5, 프락시를 사용해 값을 읽을 수도 있습니다. -- (2)
for(let key in proxy) alert(key); // test, 반복도 잘 동작합니다. -- (3)
위 예시의 Proxy
엔 트랩( handler
)이 없기 때문에 proxy
에 가해지는 모든 작업은 target에 전달됨.
proxy.test=
를 이용해 값을 쓰면 target에 새로운 값이 설정됨.proxy.test
를 이용해 값을 읽으면 target에서 값을 읽음.proxy
를 대상으로 반복 작업을 하면 target에 저장된 값이 반환됨.Proxy
의 트랩 (handler
) 은 내부 메서드의 호출을 가로챔.get
, set
행위의 내부 메서드를 말함.let numbers = [0, 1, 2];
numbers = new Proxy(numbers, {
get(target, prop) {
if (prop in target) {
return target[prop];
} else {
return 0; // 기본값
}
}
});
alert( numbers[1] ); // 1
alert( numbers[123] ); // 0 (해당하는 요소가 배열에 없으므로 0이 반환됨)
존재하지 않는 요소를 읽으려고 하면 배열은 원래
undefined
을 반환함.
하지만 예시에선 배열(객체)을Proxy
로 감싸 존재하지 않는 요소를 읽으려고 할 때 0이 반환되도록 함.
let dictionary = {
'Hello': '안녕하세요',
'Bye': '안녕히 가세요'
};
alert( dictionary['Hello'] ); // 안녕하세요
alert( dictionary['Welcome'] ); // undefined 출력.
// 하지만 이를 Proxy를 활용한다면...
let dictionary = {
'Hello': '안녕하세요',
'Bye': '안녕히 가세요'
};
dictionary = new Proxy(dictionary, {
get(target, phrase) { // 프로퍼티를 읽기를 가로챔.
if (phrase in target) { // 조건: 사전에 구절이 있는 경우
return target[phrase]; // 번역문을 반환.
} else {
// 구절이 없는 경우엔 구절 그대로를 반환.
return phrase;
}
}
});
// 사전에 없는 구절을 입력하면 입력값이 그대로 반환됨.
alert( dictionary['Hello'] ); // 안녕하세요
alert( dictionary['Welcome to Proxy']); // Welcome to Proxy (입력값이 그대로 출력됨)
// undefined가 나오지 않음!
dictionary
에 존재하지 아니한 값에 접근할때 (GET
) 기본동작이 아닌 다른 동작을 handler 를 통해 구현.
숫자만 저장할 수 있는 배열을 만들고 싶다고 가정하자.
숫자형이 아닌 값을 추가하려고 하면 에러가 발생하도록 해야함.
let numbers = [];
numbers = new Proxy(numbers, { // (*)
set(target, prop, val) { // 프로퍼티에 값을 쓰는 동작을 가로챔.
if (typeof val == 'number') {
target[prop] = val;
return true;
} else {
return false;
}
}
});
numbers.push(1); // 추가 성공.
numbers.push(2); // 추가 성공.
alert("Length is: " + numbers.length); // 2
numbers.push("test"); // Error: 'set' on proxy
// 윗 줄에서 에러 발생 -> 이후 코드 실행 불가.
push
나 unshift
같이 배열에 값을 추가해주는 메서드들은 내부에서 Set
을 사용하고 있기 때문에 메서드를 오버라이드 하지 않아도 Proxy
가 동작을 가로채고 값을 검증함.⚠️ 주의점
true
를 잊지 말고 반환해야한다!
set
트랩을 사용할 땐 값을 쓰는 것이 성공했을 때 반드시 true를 반환해줘야 함.
true를 반환하지 않았거나 falsy한 값을 반환하게 되면 TypeError가 발생함.