认识 Proxy()
Proxy是ES6新增的构造函数,主要目的是给对象中间增加了一层代理(拦截)。
形象的比喻:
Proxy就是明星的经纪人,如果你想和明星谈业务必须通过经纪人来操作
var proxy = new Proxy();
Proxy和Object.defineProperty()劫持数据有点类似,但又有区别:
Object.defineProperty()主要劫持数据,给对象进行拓展,对属性进行设置。Proxy返回一个代理对象,并不是数据劫持,通过处理目标对象后返回一个代理对象,通过操作代理对象中途可以做一些额外的操作,然后再操作实际对象
总结:Proxy的核心是怎么处理属性,defineProperty()方法的核心是怎么定义属性。
Proxy接收两个参数:
target要处理的对象handler处理程序对象handler内部有非常多的方法,本文只简单的介绍set和get方法(相关链接)
var obj = {a: 1,b: 2};var proxy = new Proxy(obj, {// get() 有两个参数,目标对象和属性值get(target, prop) {console.log("This is property value " + target[prop]);return target[prop];},// set 有三个参数,目标对象、属性值和新值set(target, prop, newVal) {target[prop] = newVal;},});console.log(obj); // {a:1, b:2}console.log(proxy); // Proxy{a:1, b:2}console.log(proxy.a);// 访问属性 a,打印以下内容:// This is property value 1// 1// 设置属性 aproxy.b = 3;console.log(obj); // {a: 1, b: 3}console.log(proxy); // Proxy {a: 1, b: 3}
Proxy还可以处理其他的数据类型。
1、处理Array
var arr = [{ name: "小明", age: 18 },{ name: "小红", age: 19 },{ name: "小王", age: 20 },];var persons = new Proxy(arr, {get(target, prop) {return target[prop];},set(target, prop, newVal) {target[prop] = newVal;},});console.log(persons[0]); // {name: '小明', age: 18}persons[0] = { name: "小张", age: 33 };console.log(persons); // Proxy {0: {…}, 1: {…}, 2: {…}}console.log(arr); // [{"name":"小张","age":33},{"name":"小红","age":19},{"name":"小王","age":20}]
2、处理函数
var fn = function () {console.log("I am a function.");};fn.a = 123;var newFn = new Proxy(fn, {get(target, prop) {return target[prop];},set() {},});console.log(newFn); // Proxy {a: 123, length: 0, name: 'fn', arguments: null, caller: null, …}console.log(newFn.a) // 123
Proxy() VS defineProperty()
当Proxy()的内部处理对象方法去操作target对象 (调用proxy的方法)的时候实际操作的仍然是target对象的方法,handler内的方法可以重写target内任何方法,因此来达到代理拦截的目的。
Object.defineProperty()和Proxy()都可以达到拦截数据的目的
但是Object.defineProperty()原则本身是给对象定义属性用的,所以当Array的push和pop等方法是无法触发setter机制的,改变数组长度、用数组的下标设置值的时候可以触发。
那么vue2.x是怎么用Object.defineProperty()做的?vue2.x是把数组相关方法全部重写,所以才导致大量的代码显得非常臃肿。
为什么vue2没有使用Proxy()?
因为ES6当时兼容不太好,而在现在ES6大量使用,所以vue3用Proxy()重写了!
而Proxy()没有这个问题,它是通过代理去操作原始数据,而defineProperty()是对原对象操作的时候进行拦截。
Reflect
Reflect是一个对象,可以用于操作目标对象的行为,它是定义的内置对象,是方法集合的容器。Reflect与Object类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与Proxy是对应的。
举例 🌰:
var obj = { a: 1, b: 2 };var proxy = new Proxy(obj, {get: function (target, prop) {// return target[prop];// 用 Reflect 代替return Reflect.get(target, prop);},set: function (target, prop, newVal) {const isOk = Reflect.set(target, prop, newVal);if (isOk) {console.log("SET successfully");}},});proxy.c = 3;console.log(proxy);
:::danger
Reflect的好处JS中好多方法都存在Object.prototype.constructor(因为都是静态方法)Reflect相当于一个的方法容器,ECMA规定未来很有很多方法都放到Reflect 上而不是Object上JS对Object的定义非常的混乱,object是广义的对象(一切皆对象),Object是狭义的对象Object存在很多共用的方法,这样很多时候都觉得不太合理,这个时候就产生了Reflect来存储方Reflect是ES6的全局的内置对象
:::
