ECMAScript 6 (12): Proxy 와 Reflect

10638 단어 자바 script
프 록 시 대상
Proxy 는 언어 차원 에서 수정 하 는 것 과 같은 기본 동작 을 수정 하 는 데 사 용 됩 니 다.그래서 프로 그래 밍 언어 를 프로 그래 밍 하 는 메타 프로 그래 밍 (meta programming) 에 속 합 니 다.프 록 시가 기본 동작 을 대리 한 것 으로 이해 된다.사용 형식 은 다음 과 같 습 니 다.
var proxy = new Proxy(target, handler);

target 은 대리 대상 이 고 handler 도 대상 입 니 다. 차단 행 위 를 맞 추고 내부 적 으로 모든 대리 행 위 를 정의 합 니 다.주의:
  • 이 에이전트 가 유효 하 기 를 원한 다 면 target 에서 호출 하 는 것 이 아니 라 proxy 대상 에서 속성 방법 을 호출 해 야 합 니 다
  • handler 를 빈 대상 으로 지정 하면 대상 은 원래 대상 과 같다
  • 받 은 proxy 는 target 의 인용 입 니 다. 대리 가 없 으 면 proxy 에서 의 수정 과 target 에서 의 수정 은 같 습 니 다
  • 간단 한 실례 를 보다
    var proxy = new Proxy({},{
      get: function(target, key){
        return 35;
      }
    });
    console.log(proxy.time);    //35
    console.log(proxy.name);    //35
    console.log(proxy.title);    //35
    //                 35

    실제로 proxy 대상 도 계승 할 수 있다.
    var proxy = new Proxy({},{
      get: function(target, key){
        return 35;
      }
    });
    var obj = Object.create(proxy);
    obj.time = 20;
    console.log(obj.time);    //20
    console.log(obj.name);    //35

    그 위력 을 느껴 보 자.
    var obj = new Proxy({}, {
      get: function(target, key, receiver){
        console.log(`getting ${key} ...`);
        return Reflect.get(target, key, receiver);
      },
      set: function(target, key, value, receiver){
        console.log(`setting ${key} ...`);
        return Reflect.set(target, key, value, receiver);
      }
    });
    
    obj.count = 1;            //setting count ...
    ++obj.count;              //getting count ...
                              //setting count ...
    console.log(obj.count);   //getting count ...
                              //2

    handler 대상 에서 get 방법 은 속성 을 나타 내 는 접근 요청, set 방법 은 속성 을 나타 내 는 기록 요청 을 알 수 있 습 니 다.물론 get 과 set 뿐만 아니 라 다음 차단 함 수 를 정의 할 수 있 습 니 다.
  • get(target, propKey, receiver = target)

  • 차단 대상 의 읽 기 속성.target 대상 이 propky 속성의 get 함 수 를 설정 할 때 receiver 는 get 함수 의 this 를 연결 합 니 다.반환 값 임 의
  • set(target, propKey, value, receiver = target)

  • 차단 대상 의 기록 속성.불 값 되 돌리 기
  • has(target, propKey)

  • propkey in proxy 연산 자 를 차단 하고 불 값 을 되 돌려 줍 니 다.
  • deleteProperty(target, propKey)

  • delete proxy [propky] 연산 자 를 차단 하고 불 값 을 되 돌려 줍 니 다.
  • enumerate(target)

  • (let i in proxy) 스 트 리밍 기 를 차단 하고 스 트 리밍 기 를 되 돌려 줍 니 다.
  • hasOwn(target, propKey)

  • proxy. hasOwnProperty (foo) 를 차단 하고 불 값 을 되 돌려 줍 니 다.
  • ownKeys(target)

  • Object. getOwnProperty Names (proxy), Object. getOwnProperty Symbols (proxy), Object. keys (proxy) 를 차단 하고 배열 을 되 돌려 줍 니 다.이 방법 은 대상 의 모든 자체 속성 을 되 돌려 줍 니 다. 옮 겨 다 닐 수 없 는 속성 을 포함 하고 Symble 속성 은 포함 되 지 않 습 니 다. 단 Object.keys(proxy) 옮 겨 다 닐 수 없 는 속성 은 포함 되 어 서 는 안 됩 니 다.
  • getOwnPropertyDescriptor(target, propKey)

  • Object. getOwnPropertyDescriptor (proxy, propkey) 를 차단 하고 속성 설명 자 를 되 돌려 줍 니 다.
  • defineProperty(target, propKey, propDesc)

  • Object. defineProperty (proxy, propkey, propDesc), Object. defineProperties (proxy, propDesc) 를 차단 하고 불 값 을 되 돌려 줍 니 다.
  • preventExtensions(target)

  • Object. preventExtensions (proxy) 를 차단 하고 불 값 을 되 돌려 줍 니 다.
  • getPrototypeOf(target)

  • Object. getPrototypeOf (proxy) 를 차단 하고 대상 을 되 돌려 줍 니 다.
  • isExtensible(target)

  • Object. isExtensible (proxy) 을 차단 하고 불 값 을 되 돌려 줍 니 다.
  • setPrototypeOf(target, proto)

  • Object. setPrototypeOf (proxy, proto) 를 차단 하고 불 값 을 되 돌려 줍 니 다.
  • apply(target, object, args)

  • proxy 인 스 턴 스 를 차단 하 는 함수 작업 은 proxy (... args), proxy. call (object,... args), proxy. application (object, args) 을 포함 합 니 다.
  • construct(target, args, proxy)

  • new 로 proxy 함 수 를 호출 하 는 동작 을 차단 합 니 다. construct () 가 돌아 오 는 것 은 대상 이 아 닌 것 이 잘못 되 었 습 니 다.
    다음은 프 록 시의 인 스 턴 스 를 열거 합 니 다.
    방문 대상 이 존재 하지 않 는 속성 오류
    var obj = new Proxy({}, {
      get: function(target, key){
        if(key in target){
          return Reflect.get(target, key);
        } else {
          throw new ReferenceError(`"${key}" is not in object`);
        }
      }
    });
    obj.look = "picture";
    console.log(obj.look);     //"picture"
    console.log(obj.sleep);    //ReferenceError: "sleep" is not in object

    배열 색인 이 마이너스 일 때 역수 위치의 값 을 되 돌려 줍 니 다.
    var origin = [10,20];
    var arr = new Proxy(origin, {
      get(target, key){
        let index = parseInt(key);
        if(index < 0){
          index = target.length + index;
          if(index < 0) return undefined;
        }
        return Reflect.get(target, index);
      }
    });
    console.log(arr[0]);     //10
    console.log(arr[1]);     //20
    console.log(arr[2]);     //undefined
    console.log(arr[-1]);    //20
    console.log(arr[-4]);    //undefined

    보호 대상 내 "" 로 시작 하 는 속성 은 사유 속성 입 니 다:
    var o = {
      "_name": "Bob",
      "age": 13,
      "_fun": function(){
        console.log("_fun is called");
      }
    };
    var obj = new Proxy(o, {
      get(target, key){
        if(key.charAt(0) === '_'){
          return undefined;
        }
        return Reflect.get(target, key);
      },
      set(target, key, value){
        if(key.charAt(0) === '_'){
          throw new Error('Cannot define a property begin with "_"');
        }
        return  Reflect.set(target, key, value);
      },
      has(target,key){
        if(key.charAt(0) === '_'){
          return false;
        }
        return Reflect.has(target, key);
      },
      deleteProperty(target,key){
        if(key.charAt(0) === '_'){
          return false;
        } else {
          Reflect.deleteProperty(..arguments);
        }
      },
      apply(target,ctx,args){
        if(target.name.charAt(0) === '_'){
          throw new TypeError(`${target.name} is not defined`);
        } else {
          Reflect apply(...arguments);
        }
      },
      defineProperty(target,key,desc){
        if(key.charAt(0) === '_'){
          return new Error(`cannot define property begin with "_"`);
        } else {
          Reflect.defineProperty(..arguments);
        }
      },
      setPrototypeOf(target,proto){
        throw new TypeError(`Cannot change the proto of ${target}`);
      },
      construct(target,ctx,args){
        if(target.name.charAt(0) === '_'){
          throw new TypeError(`${target.name} is not defined`);
        } else {
          Reflect construct(...arguments);
        }
      }
    });
    
    console.log(obj.age);    //13
    obj.age = 20;
    console.log(obj.age);    //20
    console.log(obj._name);  //undefined
    obj._hobby = "Coding";   //Error: Cannot define a property begin with "_"
    _name in key             //false
    delete obj._name;
    Object.defineProperty(obj,"_hobby",{
      value: "Coding"
    });
    Object.defineProperties(obj,{
      '_hobby': {
        value: "Coding"
      }
    });
    obj._fun();
    var a = new obj._fun();
    obj.__proto__ = {};     //Cannot define a property begin with "_"
    Object.setPrototypeOf(obj,{})    //Cannot change the proto of obj

    물론 모든 proxy 프 록 시 프 록 시 를 취소 할 수 없 는 것 은 아 닙 니 다. 아래 방법 으로 설정 한 프 록 시 는 프 록 시 를 정의 할 때 되 돌아 오 는 revoke 함수 로 취소 할 수 있 습 니 다.
    var a = {
      name:"Bob"
    };
    var {proxy, revoke} = Proxy.revocable(a, {
      get(target,key){
        return undefined;
      }
    });
    proxy.name;   //undefined;
    revoke();
    proxy.name;   //TypeError: Cannot perform 'get' on a proxy that has been revoked

    반사 대상
    Reflect 대상 은 다음 과 같은 역할 을 합 니 다.
  • Object 대상 의 뚜렷 한 언어 차원 에 속 하 는 방법 을 Reflect 에 배치
  • 일부 Object 대상 의 방법 을 수정 하여 더욱 합 리 적 으로 한다.예 를 들 어 Object.defineProperty 속성 을 정의 할 수 없 을 때 오 류 를 던 지고 Reflect.defineProperty false
  • 를 되 돌려 줍 니 다.
  • 그래서 object 의 조작 을 모두 함수 행위 로 교체 합 니 다. 예 를 들 어 Reflect.has(obj,name) 로 교체 name in obj
  • 프 록 시 에 있 는 방법 이 라면 반드시 Reflect 에서 같은 방법 을 찾 을 수 있 고 프 록 시 를 실현 할 때 기본 적 인 행 위 를 편리 하 게 완성 할 수 있 도록 보장 합 니 다.다시 말 하면 proxy 가 기본 행 위 를 어떻게 수정 하 든 Reflect 에서 진정한 기본 행 위 를 찾 을 수 있다
  • .
    프 록 시 는 추가 기능 을 추가 할 때 Reflect 를 이용 하여 원시 기능 의 실현 을 보장 합 니 다.예 를 들 어:
    var loggedObj = new Proxy({}, {
      get(target,propKey){
        console.log(`getting ${target}.${propKey}`);  //              log  
        return Reflect.get(target,propKey);
      }
    });

    Reflect 는 다음 과 같은 방법 이 있 습 니 다.
  • Reflect.getOwnPropertyDescriptor(target, propKey)

  • 같다 ObjectgetOwnPropertyDescriptor(target, propKey)
  • Reflect.defineProperty(target,propKey,desc)

  • 같다 Object.defineProperty(target,propKey,desc)
  • Reflect.getOwnPropertyNames(target)

  • 같다 Object.getOwnPropertyNames(target)
  • Reflect.getPrototypeOf(target)

  • 같다 Object.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, proto)

  • 같다 Object.setPrototypeOf(target, proto)
  • Reflect.deleteProperty(target, propKey)

  • 같다 delete target.propKey
  • Reflect.enumerate(target)

  • 같다 for ... in target
  • Reflect.freeze(target)

  • 같다 Object.freeze(target)
  • Reflect.seal(target)

  • 같다 Object.seal(target)
  • Reflect.preventExtensions(target)

  • 같다 Object.preventExtensions(target)
  • Reflect.isFrozen(target)

  • 같다 Object.isFrozen(target)
  • Reflect.isSealed(target)

  • 같다 Object.isSealed(target)
  • Reflect.isExtensible(target)

  • 같다 Object.isExtensible(target)
  • Reflect.has(target, propKey)

  • 같다 propkey in object
  • Reflect.hasOwn(target, propKey)

  • 같다 target.hasOwnProperty(propKey)
  • Reflect.ownKeys(target)

  • target 자체 의 모든 속성 을 두루 얻 을 수 있 습 니 다. 매 거 진 속성 을 포함 하고 Symbol 속성 은 포함 되 지 않 습 니 다.
  • Reflect.get(target,propKey, receiver = target)

  • propkey 가 리더 라면 리더 의 this 를 receiver 에 연결 합 니 다.
    var per = {
      bar: function(){console.log("per-bar")}
    }
    var obj = {
      get foo(){ this.bar(); },
      bar: function (){console.log("obj-bar")}
    };
    Reflect.get(obj, "foo", per);    //"per-bar"
  • Reflect.set(target,propKey, value, receiver = target)

  • propkey 가 리더 라면 리더 의 this 를 receiver 에 연결 합 니 다.
  • Reflect.apply(target, thisArg, args)
  • Function.prototype.apply.call(target, thisArg, args)thisArg.target(args) 과 같다.
  • Reflect.construct(target,args)

  • 같다 new target(...args)상기 방법 중 Reflect.set(), Reflect.defineProperty(), Reflect.freeze(), Reflect.seal(), Reflect.preventExtensions() 성공 시 true 로 돌아 가 고 실패 시 false 로 돌아 갑 니 다.대응 하 는 Object 방법 이 실 패 했 을 때 오류 가 발생 합 니 다.

    좋은 웹페이지 즐겨찾기