[JavaScript] ES6 - Proxy

알린·2024년 5월 18일
0

Web

목록 보기
7/9

Proxy

  • 객체의 속성할당하거나 읽어올 때
    객체의 속성 가져오기, 설정 및 정의와 같은 기본 객체 작업(속성 접근, 할당, 열거, 함수 호출 등)을 가로채 재정의
    👉 자동으로 값의 get, set을 인식해줌
  • 한 객체에 대한 기본 작업을 가로채재정의하는 프록시 객체 생성 가능

  • class나 Closures를 통해 객체를 설계할수 있지만, 이를 더 쉽게 설계하도록 도와줌

  • 속성 액세스를 기록하고, 입력의 유효성을 검사하고, 형식을 지정하거나, 삭제하는 데 활용

  • 일반적으로 직접 구현하지 않음
    👉 Vue3의 반응성에 Proxy가 내부적으로 사용

구성 요소

  • Target(obj)
    • Proxy할 대상
  • Handler
    • 트랩(Trap)이라고도 불리는 가로채기 메서드를 포함하는 객체
    • get, set, apply, construct 등 다양한 객체 작업을 가로챔

사용 경우

  • 데이터 검증
  • 로깅과 디버깅
  • 데이터 바인딩관찰자 패턴
    객체의 상태 변화를 감지해, 이에 따라 UI를 업데이트
  • 데이터에 대한 접근 제한

사용 방법

  • 다양한 트랩을 통해 여러 가지 작업을 가로챔

주요 트랩 메서드

  • get(target, prop, receiver): 속성에 접근할 때 호출

  • set(target, prop, value, receiver): 속성에 값을 설정할 때

  • has(target, prop): 속성이 있는지 확인할 때 (in 연산자)

  • deleteProperty(target, prop): 속성을 삭제할 때 호출 (delete 연산자).

  • ownKeys(target): 객체의 고유 속성 키를 나열할 때 호출
    (Object.getOwnPropertyNames, Object.getOwnPropertySymbols)

  • apply(target, thisArg, args): 함수 객체를 호출할 때 호출

  • construct(target, args): 생성자 함수로서 호출할 때 호출 (new 연산자)

👩🏻‍💻예시 코드

// 기본 예제
let obj = { name: '홍길동', age: 20 } // Proxy 관리가 되는 객체
const handler = {
    get(obj, prop) {
        // return obj[prop]; // undefined가 출력돼서 ui상 오류가 노출 됨!
        return prop in obj ? obj[prop] : '없는 데이터!'; // null이면 '없는 데이터!' 출력된다.
    },
}
const proxy = new Proxy(obj, handler);
document.write(proxy.name + '<br>'); // 홍길동
document.write(proxy.name2 + '<br>'); // 없는 데이터!
document.write(proxy.age + '<br>'); // 20
document.write(proxy.age2 + '<br>'); // 없는 데이터!
// 복합 예제 - member 활용
const member = {
    memberId: 'testId1234',
    name: '홍길동',
    pId: '900514-1234567',
    age: 30,
    password: 'testpassword1234',
}
const handler2 = {
    // set의 경우는 입력값 제한을 걸수 있다.
    set(obj, prop, value) {
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError('정수가 아닙니다.');
            }
            if (value < 0 || value > 200) {
                throw new RangeError('나이 범위가 아닙니다.');
            }
        }
        if (prop === 'password') {
            if (value.length < 4) {
                throw new Error('4글자 보다 적습니다.');
            }
        }
        obj[prop] = value;
    },
    // get은 외부로 데이터를 주지 않거나(private), 특정 처리가 필요할때 활용한다.
    get(obj, prop, receiver) {
        if (prop == 'password') {
            return '*'.repeat(obj['password'].length);
        }
        if (prop == 'pId') {
            return obj['pId'].substr(0, 8) + '*'.repeat(6);
        }
        if (prop in obj == false) {
            throw new Error('데이터가 없습니다.');
        }
        // return obj[prop];
        // Reflect 활용, 자동으로 get을 생성하여 전달된다.
        return Reflect.get(...arguments);
    }
}
const proxy2 = new Proxy(member, handler2);
document.write(proxy2.memberId + '<br>');
document.write(proxy2.password + '<br>');
document.write(proxy2.name + '<br>');
document.write(proxy2.age + '<br>');
document.write(proxy2.pId + '<br>');
// document.write(proxy2.name2 + '<br>'); // 데이터가 없습니다.
proxy2.age = 34;
// proxy2.age = -10; // RangeError
// proxy2.age = '10'; // TypeError
document.write(proxy2.age + '<br>');
// proxy2.password = '123'; // Error
proxy2.password = '1234';
document.write(proxy2.password + '<br>');
profile
Android 짱이 되고싶은 개발 기록 (+ ios도 조금씩,,👩🏻‍💻)

0개의 댓글