ES6的Reflect/Proxy,操作对象

1,IE 浏览器不支持 Reflect/Proxy。

Proxy用于创建一个对象的代理实例,通过处理器方法拦截对象的基本操作并可自定义操作逻辑,间接地操作目标对象。Reflect对象拥有多个静态方法,这些方法对应着对象的操作方法,可能以后新加的特性会直接加在Reflect而不是对象(Object)。Reflect的方法对应着Proxy处理器的方法。Reflect 不是构造函数,不能使用new操作符,会报错。

2,Proxy实例的创建:

let targetObj = {
    a: 'hi',
    b: 'hello'
};
//handler 可以是个空对象{},reciever是Proxy实例本身。
let handler = {
    get: function(target, prop, reciever){
        console.log('proxy get');
        return Reflect.get(target, prop);
    },
    set: function(target, prop, value, reciever){
        console.log('proxy set');
        if(prop.startsWith('_')){
            console.log('私有属性不可访问');
        }else{
            Reflect.set(target, prop, value); //当访问的属性不可写或不可配置时,返回false。
        }
        return true; //严格模式下,set方法必须返回truthy(true, 1, '1')。 
    }
};
//创建代理对象,之后不对target对象操作,而是通过对代理对象的操作间接操作目标对象。
let proxy1 = new Proxy(target, handler);
proxy1.a;
//'proxy get'
//'hi'
proxy1.a = 'haha';
//'proxy set'
//'haha'
//代理对象的操作结果会影响到目标对象,所以
target.a === 'haha'; //true.
//Proxy有个静态方法,创建Proxy实例和取消Proxy的方法。
let {proxy, revoke} = Proxy.revocable(targetObj, handler);
proxy.a; //此时的proxy实例是个拥有handler和target以及isRevoked是false的对象。
//'haha'
revoke();//调用revoke之后,proxy实例的状态发生了改变,handler和target为null,isRevoked是false
proxy.a;//此时,会报错:TypeError: Cannot perform 'get' on a proxy that has been revoked
//proxy实例可以被继承:
let obj = Object.create(proxy1, {b: 'from obj'});
Object.getPrototypeOf(obj) === proxy1;//true
obj.a;
//'proxy get'
//'haha'
obj.b;
//'from obj'

3,Proxy处理器包含着一系列可选的捕捉器,如果没有定义捕捉器,那么保持目标对象的默认行为(直接操作target)。以下是个Proxy和Reflect的应用例子(这个例子或许还不够明确地表达Proxy和Reflect的作用):

//订单
//以下是个使用Proxy代理订单对象的例子
let orderObj = {
    products: [
        {
            name: '钢笔',
            price: 12,
            number: 2
        },
        {
            name: '橡皮擦',
            price: 15,
            number: 3
        }
    ],
    totalPrice: null,
    finalPrice: null,
    coupons: [1, 5], //优惠券
    offPrice: null,
    totalOffPrice: null //offPrice + coupons
};
//
function orderProxyFactory(orderObj){
    //操作订单的方法。
    let orderOps = {
        addProduct:function(newPro){
            if(!newPro){
                return false;
            }
            var products = orderObj.products;
            if(!products){
                console.log('warning: 订单没有products属性。');
                return false;
            }

            var product = products.find(item => item.name === newPro.name);
            if(product){
                product.number +=1;
            }
            else{
                products.push(newPro);
            }
            this.recalculate();
            console.log('add product');
        },
        deleteProduct: function(name){
            if(!orderObj.products || !name){
                return false;
            }
            var products = orderObj.products;
            var product = orderObj.products.find(item => item.name === name);
            if(product){
                var index = orderObj.products.indexOf(product);
                orderObj.products.splice(index, 1);
                this.recalculate();
            }
             console.log('delete product');
        },
        changeNumber: function(name, offset){ //offset 可以是正负数
            if(!name || !offset){
                return false;
            }
            if(!orderObj.products){
                return false;
            }

            var product = orderObj.products.find(item => item.name === name);
            if(product){
                product.number += offset;
                this.recalculate();
            }
             console.log('change product');
        },
        recalculate: function(){
            if(!orderObj.products){
                orderObj.products = [];
            }
            var couponsTotal = (orderObj.coupons || [0]).reduce((coup, total) => coup + total);
            var totalPrice = 0;
            for(let prod of orderObj.products){
                totalPrice += prod.price * prod.number;
            }
            orderObj.totalPrice = totalPrice;
            orderObj.offPrice = offPricePolicy(totalPrice);
            orderObj.totalOffPrice = couponsTotal + orderObj.offPrice; 
            orderObj.finalPrice = orderObj.totalPrice - orderObj.totalOffPrice;
        }
    }

    let handler = {
        get: function(target, prop){
            //属性读取操作的捕捉器。
           if(prop in orderObj){
               console.log('读取的是订单数据');
           }
            return Reflect.get(target, prop);
        },
        set: function(target, prop, value){
            //属性设置操作的捕捉器。
           if(prop in orderObj){
               console.log('不能直接修改订单数据');
           }else{
               console.log('修改' + prop + '失败。订单没有该属性。');
           }

            return true;
        }
    };

    Object.setPrototypeOf(orderOps, orderObj);
    var opsProxy = new Proxy(orderOps, handler);  
    opsProxy.recalculate(); //初始化订单的各种价格。
    return opsProxy;

    function offPricePolicy(totalPrice){
        if(totalPrice < 80){
            return 0;
        }
        else if(totalPrice < 100){
            return 10;
        }
        else if(totalPrice < 300){
            return 20;
         }
        return 30;
    }
}
//代理可以拿到订单信息。
var orderProxy = orderProxyFactory(orderObj);
orderProxy.totalPrice;
orderProxy.addProduct({name: '书包', price: 150, number: 1});
orderProxy.changeNumber('橡皮擦', 1);
orderProxy.deleteProduct('橡皮擦');

4,Proxy处理器的其他方法:

has: function(target, prop)
//has 是in 操作符的捕捉器。Reflect的has方法跟 in操作符一样。
construct:function(target, args, newTarget)
//construct是 new 操作符的捕捉器。
apply: function(target, thisArg, args)
//apply是函数调用的捕捉器。像apply和call以及函数的普通调用。
getPrototypeOf: function(target)
//Object.getPrototypeOf方法的捕捉器。
setPrototypeOf: function(target, proto)
//Object.setPrototypeOf方法的捕捉器。设置对象原型。
defineProperty: function(target, prop, attributes)
//Object.defineProperty方法的捕捉器。
deleteProperty: function(target, prop)
//delete 操作符的捕捉器。
getOwnPropertyDescriptor: function(target, prop)
//Object.getOwnPropertyDescriptor方法
ownKeys: function(target)
//Object.getOwnPropertyNames方法 和 Object.getOwnPropertySymbols方法的捕捉器;
//但是在Object.getOwnPropertyNames(proxy)时,返回值经过filter,让结果跟各自的方法一样。
isExtensible: function(target)
//Object.isExtensible方法的捕捉器。
preventExtensions: function(target)
//Object.preventExtensions方法的捕捉器。

5,Reflect:

Reflect.apply(target, thisArgument, argumentsList)
//第三个参数是必需的。一定要传数组或类数组值。
//对一个函数进行调用操作,同时可以传入一个数组作为调用参数。
//和 Function.prototype.apply() 功能类似。
Reflect.construct(target, argumentsList[, newTarget])
//对构造函数进行 new 操作,相当于执行 new target(...args)。
//第二个参数argumentsList,一定要传数组或类数组值,若没有参数就传一个空数组。
//若第三个参数有值的话,那么构造器是newTarget,
//但实例的属性跟target的实例属性(不包括原型属性)一样:
var test = Reflect.construct(function(){this.a = 'hi';}, [], function(){this.b = 'hello';});
//test1{a:'hi'};
test.a;//'hi'
test.b;//undefined

Reflect.defineProperty(target, propertyKey, attributes)
//和 Object.defineProperty() 类似。如果设置成功就会返回 true
Reflect.deleteProperty(target, propertyKey)
//作为函数的delete操作符,相当于执行 delete target[name]。
Reflect.get(target, propertyKey[, receiver])
//获取对象身上某个属性的值,类似于 target[name]。
Reflect.getOwnPropertyDescriptor(target, propertyKey)
//类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,
//则返回对应的属性描述符,  否则返回 undefined.
Reflect.getPrototypeOf(target)
//类似于 Object.getPrototypeOf()。
Reflect.has(target, propertyKey)
//判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.isExtensible(target)
//类似于 Object.isExtensible().
Reflect.ownKeys(target)
//返回一个包含所有自身属性(不包含继承属性)的数组。
//包括不可枚举(enumerable==false)的,Symbol类型的。
//(类似于 Object.keys(), 但Object.keys()不包括 不可枚举的和Symbol类型的).
Reflect.preventExtensions(target)
//类似于 Object.preventExtensions()。返回一个Boolean。
Reflect.set(target, propertyKey, value[, receiver])
//将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
Reflect.setPrototypeOf(target, prototype)
//设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回true。

6,Proxy/Reflect是用来操作对象的,虽然某些操作对其他类型数据(比如数组)可用,可能是因为浏览器对他们的这些操作的实现原理一样。Proxy的作用比较强大,比如定义验证器、修正值(判断赋值是否合理,不合理大的修正)之类的。

7,参考文档:

MDN Proxy

runoob Proxy

8,其他文章:(后面再补上)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于"vue3proxy结合reflect"的问题,我理解你可能想了解如何在Vue 3中使用Proxy与Reflect结合起来。Vue 3是一个流行的JavaScript框架,而Proxy和Reflect则是ES6中新增的特性。 在Vue 3中,可以使用Proxy对象来代理Vue实例,以便捕获对数据的访问和修改。Proxy对象可以拦截并处理对Vue实例的操作,比如读取、设置和删除属性等。而Reflect对象提供了一组用于操作对象的方法,比如Reflect.get()、Reflect.set()和Reflect.deleteProperty()等。 结合使用Proxy和Reflect可以提供更灵活的控制和监控能力。你可以通过在Vue实例上创建一个代理对象,来拦截对数据的访问和修改,并在代理处理器中使用Reflect方法来操作实际的数据。这样可以轻松地实现对数据的拦截、校验、代理等功能。 下面是一个简单的示例代码,展示了如何在Vue 3中使用Proxy和Reflect结合起来: ```javascript const data = { message: 'Hello, Vue!', }; const proxy = new Proxy(data, { get(target, key) { console.log('Getting ' + key); return Reflect.get(target, key); }, set(target, key, value) { console.log('Setting ' + key + ' to ' + value); return Reflect.set(target, key, value); }, }); // 创建Vue应用 const app = Vue.createApp({ data() { return proxy; // 使用代理对象 }, }); app.mount('#app'); ``` 在上面的代码中,我们创建了一个名为data的普通对象,并使用Proxy对象创建了一个代理对象proxy。在代理对象的get和set处理器中,我们分别使用Reflect.get和Reflect.set来操作实际的数据。这样,当我们通过Vue实例访问或修改数据时,会触发代理处理器,并通过Reflect方法操作实际的数据。 希望这个例子能帮助到你,如果还有其他问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值