Proxy

正如Proxy的英译"代理理"所示,Proxy是ES6为了操作对象引入的API。它不直接作用在对象上,而是作为一种媒介,如果需要操作对象的话,需要经过这个媒介的同意。

使用方式
{
    //拦截读取
    let account = {
        _private: 'haha',
        id: 9999,
        name: 'admin',
        phone: '13113131313',
        create_time: '2022'
    }
    let accountProxy = new Proxy(account, {
        //拦截读取和设置操作
        //需求:对手机号中间4位换成****,创建时间换为2021
        get: function (target, key) {
            switch (key) {
                case 'phone':
                    return target[key].substring(0, 3) + '****' + target[key].substring(7)
                case 'create_time':
                    return '2021';
                default:
                    return target[key];
                    break;
            }
        },
        //需求:如果要设置的是id则不允许设置,赋值为之前的默认值,其他正常
        set: function (target, key, value) {
            if (key === 'id') {
                return target[key]
            } else {
                return target[key] = value
            }
        },
        //拦截 key in obj(判断key是否在对象中存在)
        has: function (target, key) {
            if (key in target) {
                console.log(`${key}:`, target[key]);
                return true;
            } else {
                console.log('none');
                return false;
            }
        },
        //拦截delete
        //需求:如果当前删除元素以下划线(_)开头,为私有属性,不允许删除
        deleteProperty(target, key) {
            if (key.indexOf('_') === 0) {
                console.warn('私有属性不可删除')
            } else {
                delete target[key]
                console.log('删除成功')
                return true;
            }
        },
        //拦截Object.keys() 遍历所有属性名
        //需求:如果是id或者_开头,过滤掉
        ownKeys(target) {
            return Object.keys(target).filter(function (item) {
                return item !== 'id' && item.indexOf('_') !== 0;
            })
        }
    })

    console.log(accountProxy.phone)
    console.log(accountProxy.create_time)
    console.log('---------------')
    accountProxy.id = '123';
    accountProxy.name = '李云龙';
    console.log(accountProxy.id);//改不掉
    console.log(accountProxy.name)//改掉了
    console.log('---------------')
    console.log('sex' in accountProxy)
    console.log('phone' in accountProxy)
    console.log('---------------')
    console.log('拦截删除', delete accountProxy["_private"])
    console.log('拦截删除', delete accountProxy["name"])
    console.log('---------------')
    console.log('拦截Object.keys()', Object.keys(accountProxy))

}

Snipaste_2022-03-07_13-24-27.png

Reflect

与Proxy相同,ES6引入Reflect也是用来操作对象的,它将对象里一些明显属于语言内部的方法移植到Reflect对象上,它对某些方法的返回结果进行了修改,使其更合理,并且使用函数的方式实现了Object的命令式操作.

{
    //Reflect就是操作操作对象属性和方法的另外一种方式
    //语义便于理解
    let obj = {
        name: '阿笠',
        age: '21',
        sex: 'male',
        hobbies: '烫头'
    }
    console.log(Reflect.get(obj, 'hobbies'))

    Reflect.set(obj, 'hobbies', '喝酒烫头')
    console.log(Reflect.get(obj, 'hobbies'))//语义更明显
    console.log(obj.hobbies)

    console.log(Reflect.has(obj,'name'))
}

Snipaste_2022-03-07_13-37-03.png

Proxy与Reflect实现双向数据绑定

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>你输入的是:<span id="txt"></span></h1>
<input type="text" , id="inp">
<script src="./src/proxy2.js"></script>
</body>
</html>
js
{
    //获取dom元素
    const inp = document.querySelector("#inp")
    const txt = document.getElementById('txt')

    //初始化代理对象
    const obj = {};
    //代理选项
    const handler = {
        get: function (target, key) {
            console.log('get')
            return Reflect.get(target, key)
        },
        set: function (target, key, value) {
            if (key === 'text') {
                inp.value = inp.value === value ? inp.value : value;
                txt.innerHTML = value;
            }
            return Reflect.set(target, key, value)
        }
    }
    let objProxy = new Proxy(obj, handler)

    inp.addEventListener('keyup', function (e) {
        objProxy.text = e.target.value
        console.log(objProxy.text)
    })
    objProxy.text = '123'
}

Snipaste_2022-03-07_18-56-50.png