ES6 - 反射Reflect

106 阅读2分钟

Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。

设计目的

将原本定义在Object内部的方法移动到Refelect

之前defineProperty是定义在object对象下面Object.defineProperty,现在为什么要定义在Reflect对象下面呢?

JS设计之初将很多方法设计在了Object对象下面,这样设计并不合理,将来也会有很多的方法从Object转移到Reflect

// 之前的写法
Object.defineProperty(...)


// 现在的写法
let obj = {}
let newValue = ''
Reflect.defineProperty(obj,'name',{
    get(){
        console.log('get')
        return newValue
    },
    set(val){
        console.log('set');
        newValue = val
    }
})
obj.name = 'ES6'
console.log(obj.name);

修改某些Object方法的返回结果,让其变得合理

eg: 在使用Object.defineProperty来定义对象上的某些属性的时候,有时候某些属性无法定义时就会报出异常,以前的写法就是放在try ... catch...中,因为Object.defineProperty没有返回值

try{
  Object.defineProperty
}catch(e) {
  console.log(e.message)
}

现在由于Reflecect.defineProperty()返回值是boolean,也就是将原先定义在Object上的defineProperty方法的返回值进行了改变,,让其变得合理

现在的写法:

if( Reflecect.defineProperty()){ // boolean

} else {

}

让Object操作变成函数行为

之前Object的很多操作都是命令式的

console.log('assign' in Object);                     // true

现在变成Reflect这种函数式

console.log(Reflect.has(Object,'assign'));           // true

Reflect对象的方法与Proxy对象的方法一一对应

eg: 对象中以_开头的属性,希望对外界隐藏,变成对象的私有属性,不管是get、set、delete还是遍历都是不允许的

现在改成Reflect的写法:

原先用什么钩子函数进行拦截,现在改成这种形式

Reflect.对应的钩子函数

let user = {
    name: 'lee',
    age: 32,
    _password: 'xxx'
}
user = new Proxy(user, {
    get(target, prop) {
        if (prop.startsWith('_')) {
            throw new Error('私有属性不可访问')
        } else {
            // return target[prop]
            return Reflect.get(target, prop)
        }
    },
    // 对于set一定要返回布尔类型的值
    set(target, prop, val) {
        if (prop.startsWith('_')) {
            throw new Error('私有属性不可访问')
        } else {
            // target[prop] = val
            Reflect.set(target,prop,val)
            return true
        }
    },
    deleteProperty(target,prop) {
        if (prop.startsWith('_')) {
            throw new Error('不可删除')
        } else {
            // delete target[prop]
            Reflect.deleteProperty(target,prop)
            return true
        }
    },
    ownKeys(target) {
        // return Object.keys(target).filter(item => !item.startsWith('_'))
        return Reflect.ownKeys(target).filter(item => !item.startsWith('_'))
    }
})
// 测试用例
//console.log(user._password);   // 私有属性不可访问
// console.log(user.name);        // lee
// user.age = 18
// console.log(user.age);           // 18
// try {
//     user._password = 8888 
// } catch (e) {
//     console.log(e.message);    // 私有属性不可访问
// }
// try {
//     delete user.age
// } catch (e) {
//     console.log(e.message);    
// }
// console.log(user.age);           // undefined 
// for(key in user) {
//     console.log(key);             // name age _password是被保护的属性
// }

eg: 将apply拦截器方法改成Reflect的形式

let sum = (...args) => {
    let num = 0
    args.forEach( item =>{
        num += item
    })
    return num
}

sum = new Proxy(sum,{
    apply(target,ctx,args) {
        // return target(...args) * 2
        return Reflect.apply(target,target,[...args])*2
    }
})

console.log(sum(1,2));                             // 6
console.log(sum.call(null,1,2,3));                 // 12
console.log(sum.apply(null,[1,2,3]));              // 12