1

前言:
上一节我们主要学的是【选项合并】,了解了初始化阶段各个选项的合并策略,
本节课我们来学一下【数据代理】这个知识点。

1、数据代理的定义

数据代理,也叫作数据劫持。有两个核心作用:
(1)在访问对象的属性时,可以进行其他的操作
(2)在修改对象的属性时,可以修改返回的结果
说白了,就是会自动触发一些函数(方法),在该函数(方法)中处理我们业务逻辑上的需求。

2、数据代理的种类

这里给大家介绍两种数据代理的方法:
(1) Object.defineProperty()
在一个对象上定义一个新属性,或修改现有属性,并返回这个对象。
这个方法有三个参数,分别是:
第一个是原对象,即要操作的对象
第二个是该对象的某个属性,即要操作的属性
第三个也是对象,那些会自动触发的方法就在这里面
看一个例子:

var obj = {
    name: '有鱼',
    age:2
};
Object.defineProperty(obj, 'name', {
    get() {
        console.log('访问obj时会自动调用');
        console.log(obj.age);
    },
    set(v) {
        console.log('修改obj属性时会自动调用');
        obj.age = 5;
    }
})
obj.name;// 访问obj对象的name属性,自动调用get(),输出:访问obj时会自动调用、2
obj.name = '年年';// 修改obj对象的name属性,自动调用set(),输出:修改obj属性时会自动调用,而且进行了其他操作,把age变为5
obj.name;// 再次访问obj对象的name属性,自动调用get(),输出:访问obj时会自动调用、5

但是这个数据代理的方法是有局限的,处理一层对象时没有问题,处理多层级嵌套对象及数组有一些问题,
我们那处理数组来看一下,第一个参数就是数组本身,第二个参数为数组的下标,第三个参数还是一样的,就是包含set()、get()方法的对象。
还是看代码:

var arr = ['年年', '有鱼', '卡卡'];
for(i in arr){
    Object.defineProperty(arr,i,{
        get(){
            console.log('访问arr时会自动调用'); 
        },
        set(){
            console.log('修改arr时会自动调用');
        }
    });
}
arr[1] = '楼楼';// 修改时,可以调用set(),输出:修改arr时会自动调用
console.log(arr);// 访问时,可以调用get(),输出:访问arr时会自动调用

这种情况是对原有数组修改,结果是没有问题的,但如果像 arr[3] = '楼楼' 这样新增数组时,就不可以了。
所以说为了解决这种情况,就需要使用下面的数据代理方法。
(2) Proxy()
这个数据代理方法其实也比较好理解,就是参照原对象创建一个新的代理对象,我们的操作都是在这个新对象上完成的。
它有两个参数,第一个是原来对象,第二个是含有get()、set()的对象
它的返回值就是新创建的代理对象。
而且不仅仅可以处理对象,还可以处理数组及多层级对象嵌套。
看一个例子:

var arr = ['年年', '有鱼', '卡卡'];
let obj = new Proxy(arr, {
    get: function (target, key, receiver) {
        console.log("获取时会自动调用" + key);
        return Reflect.get(target, key, receiver);
    },
    set: function (target, key, receiver) {
        console.log('修改时会自动调用');
        return Reflect.set(target, key, receiver);
    }
})

obj[2] = '楼楼';// 修改原有数据,调用set(),结果:修改时会自动调用
console.log(obj[2]);// 访问数据,调用get(),结果:获取时会自动调用2
obj[5] = '西瓜' // 添加新数据,调用set(),结果:修改时会自动调用

3、数据代理的应用场景

场景1:Vue当中的数据响应系统使用的是 Object.defineProperty()
这个应用场景后期会单独分析,今天暂不多说。
场景2:Vue渲染模板时使用的是基于Proxy()新封装的方法 initProxy()
initProxy()本质上就是对Vue实例化对象做了一层代理,用于一些数据筛选及非法拦截。
例如过滤$,_开头的Vue内部变量、js的关键字、模板使用未定义的变量等。

4、两种数据代理的利弊

Object.defineProperty和Proxy都可以实现数据代理,
前者兼容性较好,但是却无法对数组或者嵌套的对象进行代理监测,
后者基本可以解决所有的问题,但是对兼容性要求很高。

后记:
赠人玫瑰,手有余香!如果觉得文章对您有帮助,
请给一个大大的赞,还可以分享让更的人知道哦!
您也是web前端学习者,可以加VX:qingyulan52
最后祝您学习进步,早日成为技术大拿!!!
冯老师-二维码.jpg


有鱼是只猫
109 声望4 粉丝