文章目录
- 一、什么是Proxy
- 二、语法
- 三、Proxy 方法
- 1、get() 方法
- 2、set() 方法
- 3、apply() 方法
- 4、has() 方法
- 5、construct() 方法
- 6、deleteProperty() 方法
 
 
 
一、什么是Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
二、语法
var proxy = new Proxy(target, handler);
解释: Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
三、Proxy 方法
1、get() 方法
get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。
语法:
var handler = {
  get (target, propKey, ctx) {
  	return target[propKey];
  }
};
例:
var person = {
  name: "张三"
};
var proxy = new Proxy(person, {
  get: function(target, propKey) {
    if (propKey in target) {
      return target[propKey];
    } else {
      throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
    }
  }
});
console.log(proxy.name) // "张三"
console.log(proxy.age) // 抛出一个错误
运行结果:

解释: 上面代码表示,如果访问目标对象不存在的属性,会抛出一个错误。如果没有这个拦截函数,访问不存在的属性,只会返回undefined。
2、set() 方法
set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
语法:
var handler = {
  set (target, propKey, propValue, ctx) {
  	target[propKey] = propValue;
  }
};
例:
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;
    return true;
  }
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age) // 100
person.age = 'young' // 报错
person.age = 300 // 报错
运行结果:

 解释: 上面代码中,由于设置了存值函数set,任何不符合要求的age属性赋值,都会抛出一个错误,这是数据验证的一种实现方法。利用set方法,还可以数据绑定,即每当对象发生变化时,会自动更新 DOM。
3、apply() 方法
apply方法拦截函数的调用、call和apply操作。apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。
语法:
var handler = {
  apply (target, ctx, args) {
    return Reflect.apply(...arguments);
  }
};
例:
var target = function () { return 'I am the target'; };
var handler = {
  apply: function () {
    return 'I am the proxy';
  }
};
var p = new Proxy(target, handler);
p()
运行结果:

解释: 上面代码中,变量p是 Proxy 的实例,当它作为函数调用时(p()),就会被apply方法拦截,返回一个字符串。
4、has() 方法
has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。has()方法可以接受两个参数,分别是目标对象、需查询的属性名。
语法:
var handler = {
  has (target, propKey) {
  	return propKey in target;
  }
};
例:
var handler = {
  has (target, key) {
    if (key[0] === '_') {
      return false;
    }
    return key in target;
  }
};
var target = { _prop: 'foo', prop: 'foo' };
var proxy = new Proxy(target, handler);
flag = 'prop' in proxy 
alert(flag)
运行结果:

解释: 上面代码中,如果原对象的属性名的第一个字符是下划线,proxy.has()就会返回false,从而不会被in运算符发现。
5、construct() 方法
construct()方法用于拦截new命令,下面是拦截对象的写法。construct()方法可以接受三个参数: 目标对象、构造函数的参数数组、目标对象的上下文对象(this)
语法:
var handler = {
  construct (target, args, ctx) {
  	return new target(...args);
  }
};
例:
const p = new Proxy(function () {}, {
  construct: function(target, args) {
    console.log('called: ' + args.join(', '));
    return { value: args[0] * 10 };
  }
});
console.log((new p(1)).value)
运行结果:

解释: construct()方法返回的必须是一个对象,否则会报错。
6、deleteProperty() 方法
deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。deleteProperty() 方法接受两个参数:目标对象、目标属性
语法:
var handler = {
  deleteProperty (target, propKey) {
  	delete target[propKey];
  }
};
例:
var handler = {
  deleteProperty (target, key) {
    invariant(key, 'delete');
    delete target[key];
    return true;
  }
};
function invariant (key, action) {
  if (key[0] === '_') {
    throw new Error(`Invalid attempt to ${action} private "${key}" property`);
  }
}
var target = { _prop: 'foo' };
var proxy = new Proxy(target, handler);
delete proxy._prop
// Error: Invalid attempt to delete private "_prop" property
运行结果:

解释: 上面代码中,deleteProperty方法拦截了delete操作符,删除第一个字符为下划线的属性会报错。
![[Vulnhub] DC-2](https://img-blog.csdnimg.cn/6b3dc3cce27f44859f3c664bb9928495.png)


















