es6新语法Proxy对象代理和Reflect内置对象

因为之前在工作中没怎么用过Proxy,对他只是个简单的概念,最近准备面试,所以写这篇文章来恶补一下。

Proxy对象用于定义基本操作的自定义行为。这是MDN给的解释,挺绕口的是不是?简单来说,Proxy可以代理一个对象,并且自定义行为,在想要操作这个被代理对象时,是通过proxy对象去操作。
基本语法:

  let proxy = new Proxy(target,handler)
  target参数:需要被代理的对象
  handler对象:此对象中定义了操作target的自定义方法

下面,还是以代码来解释:

我现在有这样的需要,有一个对象中有id,name,age,gender属性,我们需要对对象属性做出限制要求:id属性不可修改,age属性必须是Number类型

如果是未代理的方式,我们就得需要对原对象进行逻辑修改:

let obj = {
	id:1,
	name:'lisi',
	age:18,
	setValue:function(key,value){
		if(key === 'id'){
			console.error('id属性不允许被修改')
			return
		}else{
			if(key == 'age' ){
				if(typeof value === 'Number'){
					obj[key] = value
				}else{
					console.error('age.value 必须是Number类型')
					return		
				}
			}
			obj[key] = value
		}
		obj[key] = value
	}
}
obj.setValue('id',2)		// id属性不允许被修改
obj.setValue('age','20')	// age.value 必须是Number类型

上述方法虽然可以解决,但是如果还有1个乃至更多对象有这个要求,难道要在每个对象中再写一遍这个逻辑??? 此时,我们就要用到Proxy代理实现了,代码入下

	let target1 = {
    id:1,
    name:'lisi',
    sex:20
}
let target2 = {
	name:'',
	id:2,
	sex:0
}
let handler = {
	set:function (target,key,value){
		if(key === 'id'){
			console.error('id属性不允许被修改')
			return
		}else{
			if(key == 'age' ){
				if(typeof value === 'Number'){
					target[key] = value
				}else{
					console.error('age.value 必须是Number类型')
					return		
				}
			}
			target[key] = value
		}
		target[key] = value
	}
}

let proxy1 = new Proxy(target1,handler)
proxy.name = 'zs'	// 修改成功
console.log(target1)
let proxy2 = new Proxy(target2,handler)
proxy2.name = 'lisi',
proxy2.age = 20,
proxy2.id = 2	// id属性不允许更改

要注意的是,handler中的方式名是不可以自定义的,而是Proxy提供的api
Proxy中handler常用api:

  • handler.get()
    属性读取操作的陷阱。

  • handler.set()
    属性设置操作的陷阱。

  • handler.has()

  • handler.getPrototypeOf()

  • handler.setPrototypeOf()

  • handler.isExtensible()

  • handler.preventExtensions()
    更多参考:Proxy用法
    下面是一个常用api的例子代码:

{
    // Proxy, 代理的就是对象的一些操作

    let account = {
        id: 9923,
        name: 'admin',
        _private: 'test',
        phone: '13812345678',
        create_time: '2019'
    }

    let accountProxy = new Proxy(account, {
        // 拦截读取和设置的操作
        get: function (target, key) {
            switch (key) {
                case 'phone':
                    return target[key].substring(0, 3) + '****' + target[key].substring(7)
                case 'create_time':
                    return target[key].replace('2019', 2020)
                default:
                    return target[key]
            }
        },

        set: function (target, key, value) {
            if (key === 'id') {
                return target[key]
            } else {
                return target[key] = value
            }
        },

        // d
        has: function(target, key) {
            if(key in target) {
                console.log(`${key}:`, target[key])
                return true
            } else {
                console.log('并无此属性')
                return false
            }
        },

        // 拦截delete
        deleteProperty: function(target, key) {
            if(key.indexOf('_') === 0) {
                console.warn('私有属性不能被删除')
                return false
            } else {
                delete target[key]
                return true
            }
        },

        // 拦截Object.keys()
        ownKeys(target) {
            return Object.keys(target).filter(function(item) {
                return item !== 'id' && item.indexOf('_') !== 0
            })
        }
    })

    console.log('拦截读取', accountProxy.phone, accountProxy.create_time)
    accountProxy.id = 1234
    accountProxy.name = 'guest'
    console.log('拦截设置', accountProxy.id, accountProxy.name)
    console.log('====')
    console.log('拦截in', 'sex' in accountProxy)
    console.log('====')
    console.log('拦截删除', delete accountProxy['_private'])
    console.log('拦截Object.keys()',Object.keys(accountProxy))
}

{
    let obj = {
        name: 'Nick',
        age: '32',
        sex: 'male',
        hobbies: 'swimming'
    }

    console.log(Reflect.get(obj, 'name'))
    Reflect.set(obj,'name', 'Jack')
    console.log(obj.name)
    'name' in obj
    Reflect.has(obj, 'name')
}
Reflect用法和Proxy的handler类似,但是Reflect是js的内置对象,不可构建,使用方法比较简单
let obj = {
	name:'李四',
	age:20
}
Reflect.set(obj,'name','张三')	// true,修改成功返回true
console.log(obj)	// {name:'张三',age:20}

这里也有个坑要注意:对象key名要用引号包裹,比如上面obj的name属性,那么对这个值进行修改,就是
Reflect.set(obj,‘name’,‘要修改的值’)

Reflect常用方法:

  • Reflect.set()
  • Reflect.get()
  • Reflect.has()

更多用法参考:Reflect常用方法

水平有限,这里只做基本使用的方法,仅作记录用。不喜勿喷
推荐大佬关于Proxy的解析:[Proxy解析](https://www.jianshu.com/p/c2a1aa2e2b14)
最后附上Proxy和Reflect的兼容性图示:
Proxy:
在这里插入图片描述
Reflect:
在这里插入图片描述
IE浏览器是不支持Proxy和Reflect的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值