实际在开发过程中发现,我们打印data里的数据的时候会发现,他不是我们所看到的以往的很平常的格式,他是一个proxy的格式的,如下图:
也就是说无论是什么类型的数据,都会在外面包一层proxy的包装;
这个是作什么的呢?
查资料——————————————
经过这一顿操作之后,数据就可以恢复正常的类型了,
JSON.parse(JSON.stringify(val))
关于Proxy:
Proxy可以理解成,在目标对象之前架设一层 "拦截",当外界对该对象访问的时候,都必须经过这层拦截,而Proxy就充当了这种机制,类似于代理的含义,它可以对外界访问对象之前进行过滤和改写该对象。
如果对vue2.0了解或看过源码的人都知道,vue2.0中使用 Object.defineProperty()方法对该对象通过 递归+遍历的方式来实现对数据的监控的,
当我们使用数组的方法或改变数组的下标是不能重新触发 Object.defineProperty中的set()方法的,因此就做不到实时响应了。所以使用 Object.defineProperty 存在如下缺点:
1. 监听数组的方法不能触发Object.defineProperty方法中的set操作(如果要监听的到话,需要重新编写数组的方法)。
2. 必须遍历每个对象的每个属性,如果对象嵌套很深的话,需要使用递归调用。
但是vue2.0就是用$set()方法去解决上面的这个问题,Vue3.0呢进行了升级,那就是Proxy。
Proxy基本语法
const obj = new Proxy(target, handler);
这里就和上面的截图对应上了,有木有发现呢~,再来一个详细的图;
参数说明如下:
target: 被代理对象。
handler: 是一个对象,声明了代理target的一些操作。
obj: 是被代理完成之后返回的对象。
但是当外界每次对obj进行操作时,就会执行handler对象上的一些方法。handler中常用的对象方法如下:
1. get(target, propKey, receiver)
2. set(target, propKey, value, receiver)
3. has(target, propKey)
4. construct(target, args):
5. apply(target, object, args)
如下代码演示:
const target = {
name: 'kongzhi'
};
const handler = {
get: function(target, key) {
console.log(`${key} 被读取`);
return target[key];
},
set: function(target, key, value) {
console.log(`${key} 被设置为 ${value}`);
target[key] = value;
}
};
const testObj = new Proxy(target, handler);
/*
获取testObj中name属性值
会自动执行 get函数后 打印信息:name 被读取 及输出名字 kongzhi
*/
console.log(testObj.name);
/*
改变target中的name属性值
打印信息如下: name 被设置为 111
*/
testObj.name = 111;
console.log(target.name); // 输出 111
如上代码所示:也就是说 target是被代理的对象,handler是代理target的,那么handler上面有set和get方法,当每次打印target中的name属性值的时候会自动执行handler中get函数方法,当每次设置 target.name 属性值的时候,会自动调用 handler中的set方法,因此target对象对应的属性值会发生改变,同时改变后的 testObj对象也会发生改变。同理改变返回后 testObj对象中的属性也会改变原对象target的属性的,因为对象是引用类型的,是同一个引用的。如果这样还是不好理解的话,可以简单的看如下代码应该可以理解了:
const target = {
name: 'kongzhi'
};
const testA = target;
testA.name = 'xxx';
console.log(testA.name); // 打印 xxx
console.log(target.name); // 打印 xxx
大概就是这样的,vue3.0的升级,可直接监听数组类型的数据变化
监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升。