Proxy

lee jae hwan·2022년 8월 9일

javascript

목록 보기
91/107

Proxy는 특정 객체를 감싸 프로퍼티 읽기, 쓰기와 같은 객체에 가해지는 작업을 중간에서 가로채는 객체

let proxy = new Proxy(target, handler);
let obj = {
  age:43,
};

let proxy = new Proxy(obj,{});
proxy.age1 = 1;
console.log(obj);

핸들러가 지정되지 않으면 proxy에 가해지는 모든 작업이 obj에 똑같이 적용된다.

자바스크립트 객체에는 [[prototype]]과 같은 숨김속성이 있듯이 숨김메소드가 있다.

[[Get]] get 프로퍼티를 읽을 때
[[Set]] set 프로퍼티에 쓸 때
[[HasProperty]] has in 연산자가 동작할 때
[[Delete]] deleteProperty delete 연산자가 동작할 때
[[Call]] apply 함수를 호출할 때
[[Construct]] construct new 연산자가 동작할 때
[[GetPrototypeOf]] getPrototypeOf Object.getPrototypeOf
[[SetPrototypeOf]] setPrototypeOf Object.setPrototypeOf
[[IsExtensible]] isExtensible Object.isExtensible
[[PreventExtensions]] preventExtensions Object.preventExtensions
[[DefineOwnProperty]] defineProperty Object.defineProperty, Object.defineProperties
[[GetOwnProperty]] getOwnPropertyDescriptor Object.getOwnPropertyDescriptor, for..in, Object.keys/values/entries
[[OwnPropertyKeys]] ownKeys Object.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in, Object/keys/values/entries

외부적으로 객체의 프로퍼티에 접근할땐 [[Get]]이라는 숨김메서드가 작동하고 프로퍼티에 쓸땐 [[Set]]이라는 숨김메서드가 작동하는 것이다.

이러한 숨김메소드는 당연히 사용자가 호출할 수 없는 메소드들이다.



Proxy객체는 숨김메소드를 가로채어 사용자에게 여러작업을 할 수 있도록 수 있도록 하는 객체다.

Proxy객체 사용조건

  • [[Set]]으로 값설정이 성공적으로 수행되었다면 반드시 true를 반환해야 히고 그렇지 않다면 false를 반환해야 한다.
  • [[Delete]]가 성공적으로 수행되었다면 반드시 true를 반환해야 하고 그렇지 않다면 false를 반환해야 한다.
let user = {
  name: "John",
  age: 30,
  _password: "***"
};

user = new Proxy(user,{
  ownKeys(obj){
    return Object.keys(obj).filter(key=>{
      if(!key.startsWith('_')){
        return true;
      }      
    });
  }
});

console.log(Object.keys(user));
let user = { };

user = new Proxy(user, {
  ownKeys(target) {
    return ['a', 'b', 'c'];
  }

  getOwnPropertyDescriptor(obj,prop){
    return {
      enumerable:true,
      configurable:true
    }
  }
  
});

for (const key in user) {
  console.log(key); 
}

for in, Object.keys, Object.values 메소드는 반복시 내부적으로 [[GetOwnProperty]]를 호출하여 enumerable속성을 확인한다.


Proxy를 사용하면 this가 있는 핸들러에서 this는 proxy객체를 참조하므로 오류가 발생할 수 있다.
let user = {
  name: "John",
  _password: "***",
  checkPassword(pass:string){
    return pass == this._password;
  }
};

user = new Proxy(user,{
  get(target,prop:string){
    if(prop.startsWith('_')){
      throw new Error("_ not permit");      
    }
    return (typeof target[prop] == 'function' )?target[prop].bind(target):prop;
  }
});

console.log( user.checkPassword('123') ); 

this가있는 핸들러를 get에서 바인딩하여 반환한다.


함수Proxy ``` function delay(f, ms) { return new Proxy(f, { apply(target, thisArg, args) { setTimeout(() => target.apply(thisArg, args), ms); } }); }

function sayHi(user) {
alert(Hello, ${user}!);
}

sayHi = delay(sayHi, 3000);

alert(sayHi.length); // 1 (*) 프락시는 "get length" 연산까지 타깃 객체에 전달해줍니다.

sayHi("John");


0개의 댓글