ES6 Proxy代理

概述

Proxy代理 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式。

基本用法

Proxy代理

一个 Proxy 对象由两个部分组成: target 、 handler 。在通过 Proxy 构造函数生成实例对象时,需要提供这两个参数。 target 即目标对象, handler 是一个对象,声明了代理 target 的指定行为。

let target = {   // target 可以为空对象,调用 set 方法,向目标对象中添加了 属性
    name: 'Tom',
    age: 24
}
let handler = {
    get: function(target, key) {
        console.log('getting '+key);
        return target[key]; // 不是target.key
    },
    set: function(target, key, value) {
        console.log('setting '+key);
        target[key] = value;
     return true; //严格模式下,set代理如果没有返回true,就会报错。 } } let proxy
= new Proxy(target, handler) proxy.name // 实际执行 handler.get proxy.age = 25 // 实际执行 handler.set

实例方法

1、get(target, propKey, receiver) 用于拦截某个属性的读取(read)操作,就是在读取目标对象的属性之前,搞点事情。
参数:
target:目标对象
property:属性名
receiver:操作行为所针对的对象,一般指proxy实例本身
let exam={};
let proxy = new Proxy(exam, { get(target, propKey, receiver) { console.log('Getting ' + propKey); return target[propKey]; } })
console.log(proxy.name);//undefined
2、set(target, propKey, value, receiver) 用来拦截目标对象的赋值(write)操作
参数:
target:目标对象
propertyName:属性名
propertyValue:属性值
receiver:Proxy实例本身
let validator = {
    set: function(obj, prop, value) {
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError('The age is not an integer');
                return false;    
            }
            if (value > 200) {
                throw new RangeError('The age seems invalid');
                return false;
            }
        }
        // 对于满足条件的 age 属性以及其他属性,直接保存
        obj[prop] = value;
        return true;
    }
};
let proxy= new Proxy({}, validator)
proxy.age = 100;
proxy.age           // 100
proxy.age = 'oppps' // 报错
proxy.age = 300     // 报错   

3、apply(target, ctx, args)  用于拦截函数的调用、call 和 reply 操作。

  target 表示目标对象,

  ctx 表示目标对象上下文,

  args 表示目标对象的参数数组。

function sub(a, b){
    return a - b;
}
let handler = {
    apply: function(target, ctx, args){
        console.log('handle apply');
        return Reflect.apply(...arguments);
    }
}
let proxy = new Proxy(sub, handler)
proxy(2, 1) 
// 1

4、has(target,propkey)   拦截 propKey in proxy 的操作,返回一个布尔值。即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截。

let proxy = new Proxy(exam, handler)
'name' in proxy  

5、deleteProperty(target, propKey) 拦截delete proxy[propKey]的操作,返回一个布尔值。用于拦截 delete 操作。如下是删除实例:

            var handler = {
                deleteProperty(target,key){
                    console.log('key',key);
                    invariant(key,'delete');
                    delete target[key];
                    return true;
                }
            };
            function invariant (key,action) {
                if(key[0] === '_') {
                    throw new Error(`Invalid attempt to ${action} private "${key}" property`);
                    return false;
                }
            }
            var target = {_prop:'foo',prop:'foo'};
            var proxy = new Proxy(target,handler);
            console.log("target1",target);//target1 {_prop: "foo", prop: "foo"}
            console.log("delete1",delete proxy.prop);//key prop   delete1 true
            console.log("target2",target);//target2 {_prop: "foo"}
            console.log("deletetarget",delete target._prop);//deletetarget true 直接删除
            console.log("target3",target);//target3 {}
            console.log("delete2",delete proxy._prop);//key _prop  Uncaught Error: Invalid attempt to delete private "_prop" property 通过代理则删除失败

6、construct(target, args) 用于拦截 new 命令。返回值必须为对象。

7、ownKeys(target) 用于拦截对象自身属性的读取操作。

8、getPrototypeOf(target) 拦截对象原型操作

9、isExtensible(target) 用于拦截 Object.isExtensible 操作。

扩展:

JavaScript中,对象的extensible属性用于表示是否允许在对象中动态添加新的property。ECMAScript 3标准中,所有的对象都是extensible的。ECMAScript 5标准中,所有的对象默认仍是extensible的,但可以通过设定来改变这一属性。查询一个对象是否是extensible的,可以使用Object.isExtensible()语句:

……

 

学习原文   应用学习

posted @ 2019-10-18 22:35  梁涛999  阅读(382)  评论(0编辑  收藏  举报