본문 바로가기

JavaScript

JavaScript Proxy

이 글은 아래 원문을 번역한 글로 의역이 있을 수 있습니다. 정확한 의미를 파악하고 싶으신 분은 원문을 참고해주시기 바랍니다.

 

원문: https://www.javascripttutorial.net/es6/javascript-proxy/

저작권 정보: https://www.javascripttutorial.net/es6/javascript-proxy/


개요 : 이 튜토리얼에서는 ES6의 JavaScript Proxy 개체에 대해 설명합니다.

JavaScript Proxy 개체란

JavaScript Proxy는 다른 개체(타깃)를 랩하여 대상 개체의 기본 작업을 가로채는 객체입니다.

기본 연산은 속성 조회, 할당, 열거 및 함수 호출 등이 될 수 있습니다.

프록시 개체 생성

새 프록시 개체를 만들려면 다음 구문을 사용합니다.

let proxy = new Proxy(target, handler);

다음 구문에서:

  • target은 랩할 객체입니다.
  • handler는 target의 동작을 제어하는 방법을 포함하는 객체입니다. handler 오브젝트 내부 메서드는 트랩이라고 불립니다.

단순한 프록시 예시

먼저 user 오브젝트를 정의합니다.

const user = {
    firstName: 'John',
    lastName: 'Doe',
    email: 'john.doe@example.com',
}

두 번째, handler오브젝트 정의

const handler = {
    get(target, property) {
        console.log(`Property ${property} has been read.`);
        return target[property];
    }
}

세 번째, proxy 오브젝트 생성

const proxyUser = new Proxy(user, handler);

proxyUser오브젝트는user데이터를 저장할 객체입니다. proxyUser는 user객체의 모든 속성에 액세스 할 수 있습니다.

넷째, proxyUser오브젝트를 통해 user객체의 firstName 와 lastName의 속성에 액세스 합니다.

console.log(proxyUser.firstName);
console.log(proxyUser.lastName);

출력

Property firstName has been read.
John
Property lastName has been read.
Doe

proxyUser오브젝트를 통해 user객체의 프로퍼티에 접근할때 , handler오브젝트안의 get() 메서드가 호출됩니다.

다섯째, user 원본객체를 수정하는 경우 이 변화는 proxyUser에 반영됩니다.

user.firstName = 'Jane';
console.log(proxyUser.firstName);

출력

Property firstName has been read.
Jane

마찬가지로 proxyUser의 변경은 원래 오브젝트(user)에 반영됩니다.

proxyUser.lastName = 'William';
console.log(user.lastName);

출력

William

프록시 트랩

get() trap

get() 트랩은 프록시 개체를 통해 대상 개체의 속성에 액세스할 때 실행됩니다.

이전 예제에서는 proxyUser 개체가 사용자 개체의 속성을 액세스할 때 메시지가 출력됩니다.

일반적으로 속성에 액세스할 때 get() 트랩에서 사용자 지정 로직을 개발할 수 있습니다.

 

예를 들어 get() 트랩을 사용하여 대상 개체에 대해 계산된 속성을 정의할 수 있습니다. 계산된 속성은 기존 속성의 값을 기반으로 값이 계산되는 속성입니다.

user개체에 fullName 속성이 없습니다. get() 트랩을 사용하여 firstName 및 lastName 속성을 기반으로 fullName 속성을 생성할 수 있습니다.

 

const user = {
    firstName: 'John',
    lastName: 'Doe'
}

const handler = {
    get(target, property) {
        return property === 'fullName' ?
            `${target.firstName} ${target.lastName}` :
            target[property];
    }
};

const proxyUser = new Proxy(user, handler);

console.log(proxyUser.fullName);

출력

John Doe

set() trap

set() 트랩은 target 개체의 속성이 설정될 때 동작을 제어합니다.

사용자의 연령이 18세보다 커야 한다고 가정합니다. 이 제약 조건을 적용하려면 다음과 같이 set() 트랩을 만들어야합니다.

const user = {
    firstName: 'John',
    lastName: 'Doe',
    age: 20
}

const handler = {
    set(target, property, value) {
        if (property === 'age') {
            if (typeof value !== 'number') {
                throw new Error('Age must be a number.');
            }
            if (value < 18) {
                throw new Error('The user must be 18 or older.')
            }
        }
        target[property] = value;
    }
};

const proxyUser = new Proxy(user, handler);

먼저, user의 나이를 문자열로 지정합니다.

proxyUser.age = 'foo';

출력

Error: Age must be a number.

user의 나이를 16으로 설정합니다.

proxyUser.age = '16';

출력

The user must be 18 or older.

user의 나이를 21로 설정합니다.

proxyUser.age = 21;

에러는 발생하지 않았습니다. 

apply() trap

handler.apply() 메서드는 함수호출을 위한 트랩입니다. 문법은 다음과 같습니다.

let proxy = new Proxy(target, {
    apply: function(target, thisArg, args) {
        //...
    }
});

다음의 예를보자.

const user = {
    firstName: 'John',
    lastName: 'Doe'
}

const getFullName = function (user) {
    return `${user.firstName} ${user.lastName}`;
}


const getFullNameProxy = new Proxy(getFullName, {
    apply(target, thisArg, args) {
        return target(...args).toUpperCase();
    }
});

console.log(getFullNameProxy(user)); //

출력

JOHN DOE

더 많은 트랩

다음은 기타 트랩입니다.

  • construct : new연산자를 사용을 트랩
  • getPrototypeOf : [[GetPrototypeOf]] 내부 콜을 트랩
  • setPrototypeOf : Object.setPrototypeOf 콜을 트랩
  • isExtensible : Object.isExtensible콜을 트랩
  • preventExtensions : Object.preventExtensions콜을 트랩
  • getOwnPropertyDescriptor : Object.getOwnPropertyDescriptor콜을 트랩

이 튜토리얼에서는 다른 개체의 기본 동작을 변경하기 위해 래핑하는 데 사용되는 JavaScript Proxy 개체에 대해 배웠습니다.