Proxy

概述

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

基本使用

let obj = {
  a: 1,
  b: 2
}

let proxyObj = new Proxy(obj, {
  get: function() {
      // 拦截了既有的操作,返回自己的逻辑
      return "获取值的内容"
  },
  set: function() {
      console.log("设置值的内容");
  }
})

console.log(proxyObj.a);
proxyObj.b = 20
console.log(proxyObj);

 

 

 proxyObj是设置可以拦截的对象,第一个obj参数是对应要拦截的对象内容,第二个对象参数是拦截行为,所有的行为在一个对象中

行为的内部可以设置参数

let obj = {
  a: 1,
  b: 2
}
let proxyObj = new Proxy(obj, {
  get: function(target, key) {
      // 拦截了既有的操作,返回自己的逻辑
      return `属性${key},属性值:${target[key]}`
  },
  set: function(target, key, value) {
      console.log(`属性${key},属性值:${target[key]},要设置的参数:${value}`);
  }
})
console.log(proxyObj.a);
proxyObj.b = 20
console.log(proxyObj);

 

 

 set方法主要的参数有两个,第一个target指的目标对象,key表示获取的该对象的key,

第二个set方法主要的参数有三个,第一个target指的目标对象,key表示获取的该对象的key,value表示要设置的value

Proxy可以当做原型对象

var proxy = new Proxy({}, {
  get: function(target, property) {
    return 1;
  }
});

let obj = Object.create(proxy);
console.log(obj.a)

 

 

 get方法

get方法用于拦截某个属性的读取操作。

var person = {
  name: "小明"
};

var proxy = new Proxy(person, {
  get: function(target, property) {
    // 判断当前的key是否在对应的对象上,也就是查询对象上有没有要查的这个key
if (property in target) {
// 如果有就返回这个值
      return target[property];
} else {
// 没有则抛出错误
      throw new ReferenceError("Property \"" + property + "\" does not exist.");
    }
  }
});

console.log(proxy.name )
console.log(proxy.age )

 

 

 

 get方法内部有三个参数

let obj = {
  a: 1,
  b: 2
}

let proxObj = new Proxy(obj, {
  get: function(target, key, receiver) {
      // 拦截了既有的操作,返回自己的逻辑
      return `属性${key},属性值:${target[key]}`
  }
})
console.log(proxObj.a);

 

 

 第一个target表示接受对象,第二个是获取的key,第三个表示操作对象

set方法

set方法用来拦截某个属性的赋值操作。

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // 对于age以外的属性,直接保存
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

console.log(person.age )// 100
person.age = 'young' // 报错
person.age = 300 // 报错

 

 

 

 set方法一共有4个参数,第一个参数是接受的对象,第二个参数是设置的key,第三个是设置值,第四个参数是操作对象

let obj = {
  a: 1,
  b: 2
}
let proxObj = new Proxy(obj, {
  set: function(target, key, value, receiver) {
      console.log(receiver);
      // 拦截了既有的操作,返回自己的逻辑
      return target[key] = "3"
  }
})
proxObj.b = 20
console.log(proxObj);

 

 

 apply方法

apply方法拦截函数的调用、call和apply操作。

var twice = {
  apply(target, ctx, args) {
      // Reflect.apply(...arguments)返回是对参数的累加结果
      return Reflect.apply(...arguments) * 2;
  }
};

function sum(left, right) {
  // 累加
  return left + right;
};
var proxy = new Proxy(sum, twice);
console.log(proxy(1, 2) )
console.log(proxy.call(null, 5, 6) )
console.log(proxy.apply(null, [7, 8])) 

 

 

 construct方法

construct方法用于拦截new命令,下面是拦截对象的写法。

var p = new Proxy(function() {}, {
  construct: function(target, args) {
    console.log('called: ' + args.join(', '));
    return { value: args[0] * 10 };
  }
});

new p(1).value

 

 

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

var p = new Proxy(function() {}, {
  construct: function(target, argumentsList) {
    return 1;
  }
});

new p() 

 

 

 

 Proxy 支持的拦截操作

对于可以设置、但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。

(1)get(target, propKey, receiver)

         拦截对象属性的读取,比如proxy.fooproxy['foo']

         最后一个参数receiver是一个对象,可选。

(2)set(target, propKey, value, receiver)

         拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值。

(3)has(target, propKey)

         拦截propKey in proxy的操作,返回一个布尔值。

(4)deleteProperty(target, propKey)

         拦截delete proxy[propKey]的操作,返回一个布尔值。

(5)ownKeys(target)

         拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy),返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结             果仅包括目标对象自身的可遍历属性。

(6)getOwnPropertyDescriptor(target, propKey)

         拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。

(7)defineProperty(target, propKey, propDesc)

         拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。

(8)preventExtensions(target)

         拦截Object.preventExtensions(proxy),返回一个布尔值。

(9)getPrototypeOf(target)

         拦截Object.getPrototypeOf(proxy),返回一个对象。

(10)isExtensible(target)

         拦截Object.isExtensible(proxy),返回一个布尔值。

(11)setPrototypeOf(target, proto)

         拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。

         如果目标对象是函数,那么还有两种额外操作可以拦截。

(12)apply(target, object, args)

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

(13)construct(target, args)

         拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)

 

posted @ 2021-10-26 11:15  keyeking  阅读(209)  评论(0编辑  收藏  举报