티스토리 뷰

FRONT/javascript

Proxy

성젼이 2024. 3. 8. 11:07
💡 내 공부를 위한 Proxy 정리 글이다.

 

프록시란 무엇인가?

나는 Vue.js를 주로 작업하는 프론트 개발자이다.

Vue.js에서 객체를 콘솔로 찍을 때 순수하게 객체가 아닌 Proxy로 만들어진 값들을 마주할 때가 있다.

Proxy는 왜 쓰고? 어떻게 쓰는가? 이것에 대한 글이다.

 


Why use it?

대체 왜 프록시를 쓰는가?

프록시에 공부해보니 데이터가 변환되거나 읽어지거나 여러 경우에

프록시 트랩을 통해 제공하는 기능에서 유효성 처리나 변화를 감지할 때 사용 가능하다.

내가 실무에서 프록시를 써야하는 경우라면 어떻게 쓰겠는가?

 

  • 객체를 set 해야 하는 경우 유효성 처리라던지
  • get 해야 하는데 객체 내에 값이 없을 경우 default 값을 처리해줘야 한다던지

 

주요 데이터를 처리할 때 프록시를 쓰게 될 것 같다.

궁극적으로 프록시는 어떠한 라이브러리나 기능을 만들 때에 값이나 함수에 대한 재할당, 확장을 막고 전처리를 하는 등으로
객체를 보호하거나 휴먼 에러를 막는 수단으로 사용할 것 같다.

 


How use it?

먼저 프록시는 두가지로 나뉜다 실제 객체를 뜻하는 target과 트랩을 통해 동작을 가로채는 handler이다.

 

  • target - 감싸는 객체 (실제 객체 또는 함수)
  • handler - 동작을 가로채는 트랩(trap)이 담긴 객체

handler 에 작업과 같은 트랩(get, set…) 이 있으면 이를 통해 작업이 진행되고 없다면 target 에 바로 넘긴다.

 

Proxy 구현

const target = {}
const proxy = new Proxy(target, {}) // 빈 핸들러 {} 

위와 같이 구현 시에는 Proxy 에 트랩이 없기 때문에 모든 작업은 바로 target 에 전달된다.

Trap

트랩으로 추가 가능한 핸들러 메서드는 아래 표에서 참고 할 수 있다. (참고)

내부 메서드 핸들러 메서드 작동 시점 규칙

[[Get]] get 프로퍼티를 읽을 때  
[[Set]] set 프로퍼티에 쓸 때 성공: true, 실패 : false 반환
[[HasProperty]] has in 연산자가 동작할 때  
[[Delete]] deleteProperty delete 연산자가 동작할 때 성공: true, 실패 : false 반환
[[Call]] apply 함수를 호출할 때  
[[Construct]] construct new 연산자가 동작할 때  
[[GetPrototypeOf]] getPrototypeOf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf  
[[SetPrototypeOf]] setPrototypeOf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf  
[[IsExtensible]] isExtensible https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible  
[[PreventExtensions]] preventExtensions https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions  
[[DefineOwnProperty]] defineProperty https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/definePropertyhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties  
[[GetOwnProperty]] getOwnPropertyDescriptor https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor, for..in, Object.keys/values/entries  
[[OwnPropertyKeys]] ownKeys https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNameshttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols, for..in, Object/keys/values/entries  

get 활용

const handler = {
	get : function(target, prop) {
			return prop in target ? target[prop] : '값 없음'
	}
}

const proxy = new Proxy({}, handler)
proxy.name = 'kate'

console.log(proxy.name) // kate
console.log(proxy.age) // 값 없음 

set 활용 (값 재할당 막기)

const handler = {
	// private 값은 set을 제한하고 public 값만 set을 허용한다. 
	set : function(target, key, value) {
			if (key[0] === '_') {
				return 
			}
			target[key] = value
	}
}

const test = {
	_secret: '비밀 값',
	publicValue: '공개 값',
}

has 활용

const handler = {
	has : function(target, key) {
		if(key[0] === '_') {
			return false
		}
		return key in target 
	}
}

const test = {
	_secret: '비밀 값',
	publicValue: '공개 값',
}

const proxy = new Proxy(test, handler)

console.log('publicValue' in proxy) // true 
console.log('_secret' in proxy)     // false
let range = { begin:1, end: 10 }

range = new Proxy(range, {
	has: function(target, prop) {
		return prop >= target.start && prop <= target.end
	}
})

console.log(5 in range) // true 
console.log(50 in range) // false

isExtensible, preventExtensions 활용 (객체 확장 막기)

Reflect 알아보기

Reflect 란 target객체의 상태를 boolean 으로 리턴하는 여러 메서드를 가진 자바스크립트 기본 객체이다.

const test = {
	isExtends: true
}

const handler = {
	isExtensible : function(target) {
		return Reflect.isExtensible(target) // 확장 여부를 판별 
	},
	preventExtensions : function(target) {
		target.isExtends = false
		return Reflect.preventExtenstions(target) // target 객체에 새로운 속성을 추가하지 못하도록 막는 메서드 
	}
}

console.log(Object.isExtensible(test)) // true 

Object.preventExtensions(test) // 확장 막기 

console.log(Object.isExtensible(test)) // false

apply 활용

객체가 함수로 사용될 때 쓰기 좋은 메서드이다.

어떠한 함수가 호출될 때마다 로그를 찍거나 어떠한 사전 동작을 구현할 수 있다.

const handler = {
	apply: function(target, thisArg, argumentsList) {
		console.log('호출됨', argumentsList.join(', '))
		return argumentsList[0] + argumentsList[1] + argumentsList[2] 
	}
}

const proxy = new Proxy(function(){}, handler}

console.log(proxy(1,2,3))  
// 호출됨 1,2,3
// 6

 

이렇듯 프록시를 만들어 줌으로써 트랩의 활용으로 하나의 객체를 유틸리티 함수화 할 수 있다는 점 등이 프록시를 사용하는 이유이며 이로 인해 코드의 완성도를 높일 수 있다.

 

 

참고 :

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함