js 中代理Proxy的方法以及Reflect

js 中代理Proxy的方法以及Reflect

apply(target, ctx, args)

apply(target, object, args):三个参数,分别是
目标对象(目标对象得是函数)
目标对象的上下文对象(this)(需要手动设置的)
目标对象的参数数组。

用于拦截函数的调用、call 和 reply 操作。target 表示目标对象,ctx 表示目标对象上下文,args 表示目标对象的参数数组。

拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。

   let target = function () {
     
          console.log("猫抓老鼠!");
        };

        let p = new Proxy(target, {
     
          apply: function () {
     
            target();
            function dog() {
     
              console.log("狗管闲事!");
            }
            dog();
          },
        });
	//拦截target函数。
        p();//猫抓老鼠
			//狗管闲事!

has(target, propKey)

用于拦截 HasProperty 操作,即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截。此方法不判断一个属性是对象自身的属性,还是继承的属性

注意:此方法不拦截 for … in 循环。

    let obj = {
      _porp: "foo", porp: "foo" };

        let p = new Proxy(obj, {
     
            has : function(target, key){
     
              // 添加新的功能
              if(key[0] == "_"){
     
                  return false;
              }

              return key in target;
            }
        });

        console.log('_porp' in p);

construct(target, args)

construct方法可以接受两个参数。
target:目标对象
args:构造函数的参数对象

construct方法返回的必须是一个对象,否则会报错。

  function Person(name) {
     
        this.name = name;
      }
 	let p = new Proxy(Person, {
     
            construct : function(target, args){
     
                target.prototype.say = function(){
     
                    console.log("我会说虎牙!");
                }
              //  return new target(...args);
              return Reflect.construct(target,[...args]);
            }
        });

       let zhangsan =  new p("张三");

       console.log(zhangsan.name);
       zhangsan.say();

deleteProperty(target, propKey)

deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。

    let obj = {
     
          _porp: "123",
        };
      console.log(obj);
      delete obj._porp
      console.log(obj);

        let p = new Proxy(obj, {
     
          deleteProperty: function (target, key) {
     
            if (key[0] == "_") {
     
              throw new Error("删除错误!或者该属性不能删除!");
            }
            delete target[key];
          },
        });
        console.log(p);
        delete p._porp;
        console.log(p);

defineProperty(target,key,descriptor)

 {
     
           var handler = {
     
               defineProperty:function(target,key,descriptor) {
     
                   console.log(descriptor);
                   target[key] = descriptor.value;
                // return true;无效
                  // return false;
               }
           };
           var target = {
     };
           var proxy = new Proxy(target,handler);
           proxy.foo = 'bar'
           console.log('proxy添加新的属性:',proxy);
           console.log(target.foo);
}

​ Proxy代理内的definneProperty方法return true/false并没有任何意义。

​ 当目标对象添加属性的方法被拦截defineProperty方法若不添加 target[key] = descriptor.value;,则不能添加属性。

​ 注意,如果目标对象不可扩展(non-extensible),则defineProperty不能增加目标对象上不存在的属性

​ 否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),

​ 则defineProperty方法不得改变这两个设置。

输出结果

js 中代理Proxy的方法以及Reflect_第1张图片

getOwnPropertyDescriptor

getOwnPropertAyDescriptor方法拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined。

   let obj = {
      _porp: "foo", porp: "foo" };

        let p = new Proxy(obj, {
     
          getOwnPropertyDescriptor: function (target, key) {
     
            if (key[0] == "_") {
     
              throw new Error("查找错误!或者该属性不能查找!");
            }
            return Object.getOwnPropertyDescriptor(target, key);
          },
        });

        console.log(Object.getOwnPropertyDescriptor(p, "porp"));

        function a() {
     
          console.log("开始游戏!");
        }

        if (init == true) {
     
          a();
        }
      let init = true;
      let p = new Proxy(a, {
     
        apply: function (target) {
     
          if(init == true){
     
              target();
          }else{
     
              console.log("武器系统还没冷却!");
          }
        },
      });
      //
      p();

getPrototypeOf方法

getPrototypeOf方法主要用来拦截获取对象原型。具体来说,拦截下面这些操作。

Object.prototype.proto
Object.prototype.isPrototypeOf()
Object.getPrototypeOf()
Reflect.getPrototypeOf()
instanceof

js 中代理Proxy的方法以及Reflect_第2张图片

左侧代码中,getPrototypeOf方法拦截Object.getPrototypeOf(),返回proto对象。
注意: getPrototypeOf方法的返回值必须是对象或者null,否则报错。另外,如果目标对象不可扩展(non-extensible), getPrototypeOf方法必须返回目标对象的原型对象。

isExtensible()方法

isExtensible方法拦截Object.isExtensible操作。

左侧代码设置了isExtensible方法,在调用Object.isExtensible时会输出called。

注意,该方法只能返回布尔值,否则返回值会被自动转为布尔值。

这个方法有一个强限制,它的返回值必须与目标对象的isExtensible属性保持一致,否则就会抛出错误( 如下所示 )

js 中代理Proxy的方法以及Reflect_第3张图片

ownKeys()方法

ownKeys方法用来拦截对象自身属性的读取操作。具体来说,拦截以下操作。

Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
for…in循环

注意,使用Object.keys方法时,有三类属性会被ownKeys方法自动过滤,不会返回。

目标对象上不存在的属性
属性名为 Symbol 值
不可遍历(enumerable)的属性

		let obj = {
      _a: 1, b: 2, c: 3 };	
        Object.defineProperty(obj, "_a", {
     
            //遍历
            enumerable : false
        });
      //   for (let key in obj) {
     
      //     console.log(key, obj[key]);
      //   }

        let p = new Proxy(obj, {
     
            ownKeys : function(target){
     
              console.log(target)
              return ["_a", "b", "c", "d"];
            }
        });

      //  console.log(Object.keys(p))

        for (let key in p) {
     
          console.log(key, obj[key]);
        }

preventExtensions方法

preventExtensions方法拦截Object.preventExtensions()。该方法必须返回一个布尔值,否则会被自动转为布尔值。
这个方法有一个限制,只有目标对象不可扩展时(即Object.isExtensible(proxy)为false),proxy.preventExtensions才能返回true,否则会报错。

js 中代理Proxy的方法以及Reflect_第4张图片

setPrototypeOf方法

setPrototypeOf方法主要用来拦截Object.setPrototypeOf方法

注意,该方法只能返回布尔值,否则会被自动转为布尔值。另外,如果目标对象不可扩展(non-extensible),setPrototypeOf方法不得改变目标对象的原型。

Proxy.revocable()方法

Proxy.revocable方法返回一个可取消的 Proxy 实例。

js 中代理Proxy的方法以及Reflect_第5张图片

Proxy.revocable方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例。上面代码中,当执行revoke函数之后,再访问Proxy实例,就会抛出一个错误。
Proxy.revocable的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。

Reflect

ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。

Reflect 对象对某些方法的返回结果进行了修改,使其更合理。

说明:比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false

Reflect 对象使用函数的方式实现了 Object 的命令式操作。

保持和proxy对象的方法一一对应

Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

Proxy(target, {
     
  set: function(target, name, value, receiver) {
     
    var success = Reflect.set(target, name, value, receiver);
    if (success) {
     
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});

静态方法:

Reflect对象一共有 13 个静态方法。

  • Reflect.apply(target, thisArg, args)
  • Reflect.construct(target, args)
  • Reflect.get(target, name, receiver)
  • Reflect.set(target, name, value, receiver)
  • Reflect.defineProperty(target, name, desc)
  • Reflect.deleteProperty(target, name)
  • Reflect.has(target, name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)

arget, name, desc)

  • Reflect.deleteProperty(target, name)
  • Reflect.has(target, name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)

这部分具体请google

你可能感兴趣的:(前端,js,proxy,js,javascript,html,css3)