React, Vue 같은 라이브러리나 프레임워크들을 쓰는 목적은 여러가지가 있겠지만 하나의 페이지에서 데이터를 동적으로 변경하기 위함(SPA)도 있을 것 이다.
Vue에 대해 공부하던 중 Vue는 일반 객체를 제외한 반응형 객체들은 변경사항을 추적하기 위해 Proxy 객체로 변환한다는 사실을 알게 되었고 관련된 개념이 모자라 간단히 정리해보려고 한다.
반응성 (Reactivity)
Vue 공식 문서에선 반응성(Reactivity)에 대해, "변경"에 대한 제어를 선언적으로 수행하는 프로그래밍 패러다임이라고 나와 있다.
간단히 말해 내부에서 변경을 어떤식으로 이루어지게 하는지보다 해당 방식을 통해 변경을 이뤄지게 하겠다에 대해 중점이 맞춰진 방식이란 말이다. (여기서 선언형 프로그래밍이 이해가 되지 않는다면 다음 글을 읽어 보자.)
반응성에 대해 알아볼 수 있는 좋은 사례는 엑셀 시트이다.
sum에는 a와 b의 선언된 값을 더한 값이 저장되도록 해두었다.
그래서 sum에 직접적으로 값을 바꾸지 않더라도 a의 값만 바뀌면 sum의 값도 저절로 바뀌게 된다.
Javascript에서는 이런식으로 동작하지 않는다. 다음 코드를 보자.
let data = {A: 30, B: 50}
let sum = data.A + data.B;
console.log(sum) // 80
data.A = 50
console.log(data) // {A: 50, B: 50} <-- data내의 A의 값은 바뀜
console.log(sum) // 80 <-- 바뀌지 않음.
data.A의 값은 바뀌였지만 sum의 값은 바뀌지 않았다.
그럼 위의 엑셀 시트와 같은 기능을 JS에서 구현하려면 어떻게 해야 할까?
JS에서는 getter/setter나 Proxy를 통해서 구현해볼 수 있을 것 같다.
// JS getter/setter를 이용한 사례
const data = {
A: 30,
B: 50,
get sum() {
return data.A + data.B;
},
set numA(numA) {
this.A = numA
},
set numB(numB) {
this.B = numB
}
}
console.log(data.A); // 30
console.log(data.B); // 50
data.numA = 50; // setter 실행
console.log(data.sum()) // 100, getter 실행
// JS Proxy를 이용한 사례
const data = {
A: 30,
B: 50,
};
const proxyData = new Proxy(data, {
get(target, prop) {
if (prop === "sum") {
return target.A + target.B;
}
return target[prop];
},
set(target, prop, value) {
if (prop === "A" || prop === "B") {
target[prop] = value;
return true;
}
console.error("A와 B 속성만 수정할 수 있습니다.");
return false;
}
});
console.log(proxyData.sum); // 80
proxyData.A = 50;
console.log(proxyData.sum); // 100
Proxy 객체는 뭐길래 이런 기능을 할 수 있게 해주는 걸까?
Proxy 란?
Proxy 객체는 ES2015부터 추가된 객체이다.
서버에 대해 조금 알고 있다면, 클라이언트와 서버 사이의 중개인 역할을 해 데이터를 전달해주는 프록시 서버를 생각해보자.
그럼 Proxy 객체에 대한 개념을 조금 더 쉽게 이해할 수 있을 것 같다.
Proxy는 특정 객체를 감싸 프로퍼티 읽기, 쓰기와 같이 객체에 가해지는 작업을 중간에서 가로채는 객체로, 가로채진 작업은 Proxy 에서 처리되거나 감싸진 원래의 객체가 처리하도록 전달하는 역할을 한다.
문법은 다음과 같다.
let proxy = new Proxy(target, handler)
target – Proxy의 대상이 될 감싸질 객체. 함수를 포함한 모든 객체가 가능하다.
handler – 동작을 가로채는 메서드인 '트랩(trap)'이 담긴 객체. handler를 통해 proxy를 설정한다.
아래 그림은 위의 설명을 잘 나타내고 있다.
Proxy는 target을 감싸 target내의 프로퍼티인 test를 값을 읽으려는 get 작업을 가로채고 있다.
이 과정을 코드로 나타내면 다음과 같다.
const target= {};
let proxy = new Proxy(target, {})
proxy.test = 5; // proxy 객체에 새 프로퍼티 추가
console.log(proxy.test) // 5
console.log(target.test) // 5 <- 원본 객체에도 반영됨.
Proxy는 일반 객체와는 다른 행동 양상을 보이는 '특수 객체(exotic object)'이다. 그렇기에 자체적인 프로퍼티가 없다.
만약 handler가 비어있다면 Proxy에 가해지는 작업은 target에 곧바로 전달된다.
아래 사진은 handler를 통해 가로챌 수 있는 메서드들을 나타낸 사진이다.
참고
깊은 반응성 | Vue.js
깊은 반응성 이제 좀더 깊게 들어가 볼까요! vue를 다른 기술과 구분짓는 것은 비간섭적인 반응성 시스템(unobtrusive reactivity system)입니다. vue에서 모델은 Model은 프록시로 감싸진 자바스크립트 객
vueframework.com
Vue.js
Vue.js - The Progressive JavaScript Framework
vuejs.org
Proxy와 Reflect
ko.javascript.info
'개발 > Javascript' 카테고리의 다른 글
만약 영상에 배속기능이 없다면? (ex. 학교 강좌) (4) | 2022.08.12 |
---|---|
Javscript의 Math.random과 정규분포에 대해 (0) | 2022.01.28 |
OverRiding(오버라이딩)과 OverLoading(오버로딩) 간단 정리 (0) | 2021.06.05 |
간단하게 훑어보는 함수형 프로그래밍 #1 (0) | 2020.05.04 |
ES6 Class (0) | 2020.04.23 |