Proxy和Reflect

本文深入探讨了JavaScript中Proxy和Reflect对象的使用方法及其在元编程中的作用。详细讲解了如何利用Proxy拦截对象操作,以及Reflect提供的语言内部方法,包括数据类型校验的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Proxy概念

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Proxy和Reflect</title>
</head>
<body>
<script>
//monitor是obj是代理,对monitor的操作最后会映射给obj
{
    let obj = {
        time: '2019-3-16',
        name: 'net',
        _r: 123
    }
    let monitor = new Proxy(obj, {
        //拦截对象属性的读取
        get (target, key) {
            return target[key].replace('2019', '2020');
        },
        //拦截对象属性的设置
        set (target, key, value) {
            if (key === 'name') {
                return target[key] = value;
            } else {
                return target[key];
            }
        }
    });

    console.log(obj.time);//2019-3-16
    console.log(monitor.time);//2020-3-16

    monitor.time = '2020';
    console.log(monitor.time);//2020-3-16
    monitor.name = 'hello';
    console.log(monitor.name);//hello
}

//判断当前对象中是否有某个属性key in obj
{
    let obj = {
        time: '2019-3-16',
        name: 'net',
        _r: 123
    }
    let monitor = new Proxy(obj, {
        has(target, key) {
            if (key === 'name') {
                return target[key];
            } else {
                return false;
            }
        }
    });

    console.log('name' in obj);//true
    console.log('_r' in obj);//false
}

//拦截删除操作
{
    let obj = {
        time: '2019-3-16',
        name: 'net',
        _r: 123
    }
    let monitor = new Proxy(obj, {
        deleteProperty(target, key) {
            if (key.indexOf('_') > -1) {
                delete target[key];
                return true;
            } else {
                return target[key];
            }
        }
    });

    delete monitor.time;
    console.log(monitor.time);//2019-3-16
    delete monitor._r;
    console.log(monitor._r);//undefined
}

//拦截Object.keys  Object.getOwnPropertySymbols  Object.getOwnPropertyNames
{
    let obj = {
        time: '2019-3-16',
        name: 'net',
        _r: 123
    }
    let monitor = new Proxy(obj, {
        ownKeys(target) {
            return Object.keys(target).filter(item => item != 'time');
        }
    });
    console.log(Object.keys(monitor));
    //(2) ["name", "_r"]
}
</script>
</body>
</html>

Reflect对象的设计目的

  • 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
  • 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false
  • 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
  • Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Proxy和Reflect</title>
</head>
<body>
<script>
//Proxy有的方法Reflect都有
{
    let obj = {
        time: '2019-3-16',
        name: 'net',
        _r: 123
    }
    console.log(Reflect.get(obj, 'time'));//2019-3-16
    Reflect.set(obj, 'name', 'hello');
    console.log(obj.name);//hello
    console.log(Reflect.has(obj, 'name'));//true
}            
</script>
</body>
</html>

数据类型校验例子

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Proxy和Reflect</title>
</head>
<body>
<script>
//数据类型校验,实现校验和业务解耦
function validator(target, condition) {
    return new Proxy(target, {
        _condition: condition,
        set (target, key, value, proxy) {
            if (target[key]) {
                let va = this._condition[key];
                if (!!va(value)) {
                    return Reflect.set(target, key, value, proxy)
                } else {
                    throw Error(`不能设置${ key }为${ value }`);
                }
            } else {
                throw Error(`不存在 ${ key }`);
            }
        }
    });
}

const personCondition = {
    name(val) {
        return typeof val === 'string';
    },
    age(val) {
        return typeof val === 'number' && val > 18;
    }
}

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
        return validator(this, personCondition);
    }
}

var person = new Person('zhangsan', 30);
console.log(person);
//Proxy {name: "zhangsan", age: 30}

person.name = 22;
//Uncaught Error: 不能设置name为22

person.age = 12;
//Uncaught Error: 不能设置age为12

person.abc = 11;
//Uncaught Error: 不存在 abc
</script>
</body>
</html>

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值