자바스크립트 프록시

Sheryl Yun·2022년 10월 11일
0
post-thumbnail

프록시(Proxy)라는 건 네트워크나 CORS 에러 처리 때 들어본 개념이다. 자바스크립트 언어 자체에도 프록시라는 개념이 있다니 신기했다. 프록시는 어디에 쓰이든 항상 '중간'에서 뭔가를 해주는 역할인 것 같았다. MDN의 프록시의 정의부터 시작해보자.

프록시란?

프록시 객체는 조회, 할당, 열거, 호출 등의 기본적인 작업들에 대해 사용자(개발자) 지정 동작을 추가로 정의하는 데 사용된다.

한 마디로 프록시를 사용하면 개발의 본 흐름 도중에 추가로 동작을 정의(대문자화, 값 수정, 에러 시 콘솔 출력 등)하기가 매우 용이하다.

아래에서 좀 더 자세히 알아보자.

프록시 만들기

프록시 객체의 형태는 다음과 같이 두 개의 인자를 받는다.

var x = new Proxy(target, handler);

  • target프록시를 적용할 객체를 의미하며 다른 객체나 프록시, 함수 등 뭐든지 가능하다.
  • handler프록시에서 어떤 동작을 추가로 수행할 것인지를 정의한다. 일반 함수 형태(함수명( ) { })화살표 함수 형태(함수명: ( ) => { }) 또는 객체의 메서드 형태(함수명: function( ) { })로 get set을 정의한 객체이다.

코드

// 프록시를 적용할 객체 (target)
const dog = { breed: "German Shepherd", age: 5 };

// 프록시 생성
const dogProxy = new Proxy(dog, {
	// handler 객체에 게터와 세터 정의
	get(target, breed) {
    	return target[breed].toUpperCase(); // breed를 대문자화하여 반환
    },
    set(target, breed, value) {
    	console.log("breed 수정");
        target[breed] = value; // '할당'으로 들어온 value값으로 breed 수정
    },
});

// 객체의 프로퍼티를 출력하는 형태가 '할당'인지 여부에 따라 get이 호출될지, set이 호출될지가 결정된다.
console.log(dogProxy.breed); // 할당이 아니므로 get 호출 (대문자 GERMAN SHEPHERD 반환)

console.log(dogProxy.breed = 'Labrador'); // 할당이므로 set 호출 (breed 수정)
console.log(dogProxy.breed); // 다시 get 호출 (LABRADOR 반환)

프록시는 어디에 유용할까?

프록시는 다음과 같은 경우에 활용하면 유용하다.

  1. 데이터검증할 때 (특정 조건일 때와 아닐 때 각각 다른 동작 수행)
  2. 동일한 형태의 게터와 세터가 여러 개의 프로퍼티에 중복될 때

데이터 검증

// 프록시에서 handler로 쓰일 함수(age 검증)를 '객체의 메서드' 형태로 선언
const validateAge = {
	set: function(object, property, value) { // '할당'으로 호출하면 자동으로 이 세 값을 인자로 받음
        // 검사하려는 property가 'age'인지를 먼저 검증
    	if (property === 'age') {
        	// 새롭게 수정할 age값(value)이 18 이상인지 검증
        	if (value < 18) {
            	throw new Error('성인이 아닙니다!');
            } else {
            	object[property] = value; // 객체의 age 프로퍼티의 값을 value로 지정하고,
                return true; // true 반환 (프로퍼티 수정에 성공했다는 뜻 - 또다른 곳에서 검증에 사용할 때)
            }
        }
    }
};

// 프록시 생성 (target은 빈 객체, handler는 위에 정의한 validateAge 함수)
const user = new Proxy({}, validateAge);

// '할당'을 하면 handler의 set(세터)을 호출
user.age = 17; // Uncaught Error: 성인이 아닙니다!

user.age = 21; // (성인이 맞으므로) 21로 설정 성공 (실제 호출하려면 get(게터) 필요)

동일한 형태의 게터 세터 중복 없애기

이 경우는 프록시를 활용하지 않았을 때와 프록시를 활용했을 때를 비교해서 살펴보겠다.

먼저 프록시를 활용하지 않은 상황이다.

// 객체인데 '클래스' 역할이라서 get set을 모두 포함하는 dog 객체이다.
// 아직은 프로퍼티가 _name, _age밖에 없지만 더 늘어나면 그만큼 get set을 추가로 정의해야 할 것이다.
const dog = {
	_name: 'pup', 
    _age: 7,
    
    get name() {
      console.log(this._name);
    },
    get age() {
      console.log(this._age);
    },
    
    set name(newName) {
    	this._name = newName;
        console.log(this._name);
    },
    set age(newAge) {
    	this._age = newAge;
        console.log(this._age);
    }
};

dog.name; // pup (get 호출)
dog.age; // 7 (get 호출)

dog.breed; // 없는 프로퍼티이므로 undefined
dog.name = 'Max'; // 할당을 통해 수정 (set 호출)
dog.name; // (수정 후) Max (get 호출)

여기서 잠깐!

프로퍼티 앞에 "_(언더바)"를 붙이면 자바스크립트의 관습상 private(클래스 내부에서만 접근이 가능한 속성)이라는 의미이다.

get set 이름과 객체의 프로퍼티 이름이 같으면 set 안의 this가 세터를 계속 호출하여 무한 루프가 발생한다.

set name(newName) {
	this.name = newName; // 세터(name)를 다시 무한 호출
}

프로퍼티 앞의 언더바는 위와 같은 상황을 방지하기 위한 네이밍 관습이다.

만약 get set의 이름을 'getname, rename' 식으로 프로퍼티의 이름과 겹치지 않게 지으면 언더바를 쓰지 않아도 된다.

set rename(newName) {
	this.name = newName;
}

이제 프록시 개념을 활용하여 위의 중복된 형태의 코드들을 handler로 합쳐보자.

const dog = {
	name: 'pup',
    age: 7,
};

// 위에서 쭉 늘어져있던 get set들을 handler를 통해 하나로 합쳤다.
const handler = {
	get: (target, property) => {
    	// in으로 property가 있는지 먼저 검증
        property in target ? console.log(target[property]) : console.log('객체에 해당 property 없음');
    },
    set: (target, property, value) => {
    	target[property] = value;
        console.log('잘 수정됨: ' + target[property]);
    },
};

// 프록시 생성
const dogProxy = new Proxy(dog, handler);

dogProxy.name; // pup
dogProxy.age; // 7

dogProxy.name = 'Max'; // 잘 수정됨: Max
dogProxy.age = 8; // 잘 수정됨: 8

dogProxy.breed; // 객체에 해당 property 없음

이제 프로퍼티가 아무리 늘어나도 handler가 프로퍼티의 모든 get set을 처리해준다 👏

이렇게 프록시를 활용하면 get set을 사용하기 전에 데이터를 검증하거나 콘솔 출력과 같은 추가적인 동작을 편하게 지정할 수 있다. 또 handler 개념을 활용하여 중복되는 형태의 get set을 간결하게 처리할 수도 있다.

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글