vue3.0发布后,在双向数据绑定这里,使用proxy代替了object.defineProperty,众所周知,obj.defineProperty是对对象属性监听,循环对象,一个个属性监听,proxy是对一整个对象进行监听。而proxy的一大优势就是可以监听数组。此帖用来记录自己对proxy的调研理解。

1,proxy的基本理解

proxy是es6中的语法,最为代理的功能,当外接要访问对象的时候,proxy可以做一层拦截,并且可以对这个proxy代理进行操作,进而实现对对象的操作。如:

var proxy = new Proxy(obj, handler)

这里定义的proxy作为obj的代理,handler也是个对象,在这里进行操作,proxy和obj始终保持状态一直,proxy进行了什么操作之后,obj同样做出改变,是一个对obj全对象的监听。目前有14拦截操作,具体可看es6文档。

2,proxy和reflect关系

reflect也是es6的语法,再proxy使用中常用到reflect,reflect有14中方法,对应proxy是一样的,但是这俩其实没关系,只是搭配着使用,proxy用来拦截,reflect用来操作。

var obj = {
    a: 1,
    c: 3
};
var proxy = new Proxy(obj, {
    get: function(target, key, receiver) {
        console.log('get的key为 ===>' + key);
        return Reflect.get(target, key, receiver);
    },
    set: function(target, key, value, receiver) {
        console.log('set的key和value为 ===>' + key, value);
        return Reflect.set(target, key, value, receiver);
    }
});
proxy.b         //get的key为 ===>b
proxy.a  = 5   //set的key和value为 ===>a 5
proxy.b = 2    //set的key和value为 ===>b 2

第一个proxy.b,没有赋值操作直接点一个属性,这时候走的就是get方法,Reflect返回的就是key,也就是b。
第二个给代理对象proxy的a复制5,走的就是set方法,里面的Reflect.set是把value值赋给当前对象的key,就是把5赋给a。

3,为什么可以监听数组

运行下面代码:

  let arr = [1,2,3]
  let proxy = new Proxy(arr, {	
 	get: function (target, key, receiver) {
         console.log('get的key为 ===>' + key);
         return Reflect.get(target, key, receiver);
     },
     set(target, key, value, receiver){
         console.log('set的key为 ===>' + key, value);
         return Reflect.set(target, key, value, receiver);
     }
 })
 proxy[0]          // set的key为 ===>0
 proxy[3] = 12     // set的key为 ===>3  12

可以看到,和上面obj的时候结果一样,key值是索引,如果使用数组的方法呢?

proxy.push('2')
// get的key为 ===>push
// get的key为 ===>length
// set的key为 ===>3 2
// set的key为 ===>length 4
console.log(proxy, 'proxy的length=' + proxy.length)
console.log(arr, 'arr的length=' + arr.length)
// get的key为 ===>length
// Proxy {0: 1, 1: 2, 2: 3} "proxy的length=3"
//  [1, 2, 3] "arr的length=3"

可以看到,get方法走了两边,set方法走了两边。因为push方法其实做了两步,第一是再length出加上push的值,第二是把length加一,所以走了两边。

原因:
从代码执行上看,确实是可以监听数组,分析下,首先,数组其实也是对象,从 typeof方法可以看出来,不然,数组也不能使用.length,[0],.push()等,如果把数组写成类数组对象,就好理解多了。

let objArr = {
	'0': 1,
	'1': 2,
	length: 2,
	push: Array.prototype.push(),
	...
}

从console的结果所以可以看出,这里的proxy就是个类数组。那么可以猜想,如果proxy第一个参数传的是数组时,proxy就会转化成类数组,也可以调用数组的方法,length、push等,找不到的方法就去原型链上找。

所以,如果数组长度改变,key值就是length,调用push等方法,key就是push。这样一切就理的通了。当然这也是我个人再学习proxy时候的一些理解,也或许是这样或许不是这样,但我这样去理解确实会明白多,如果不对的话希望大家看了之后可以纠正指点。

Logo

前往低代码交流专区

更多推荐