ES6之Proxy

本文介绍了ES6中的Proxy特性,用于修改默认行为,实现元编程。讲解了Proxy的功能,如访问拦截和改写,并详细阐述了get、set等实例方法的用法。还提及了Proxy.revocable用于创建可撤销的Proxy实例,以及在响应式数据和数据校验方面的应用。
摘要由CSDN通过智能技术生成

概述

  • 修改默认行为,元编程
  • 功能:访问拦截改写,代理器
  • 语法
    let p = new Proxy(target, handler);
    
    • target:被拦截目标
    • handler:定制拦截行为
/**
 * 常见参数
 * target: 目标对象(函数)
 * property: 被设置的属性名
 * value: 被设置的新值
 * receiver: 最初被调用的对象(通常是proxy本身)
 * thisArg: 被调用时的上下文对象
 * argumentsList: 被调用时的参数数组
 */

实例方法

  • get
/**
 * get,重载对象读取属性运算
 */
var obj = new Proxy({}, {
    get(target, property, receiver) {
        return 'run get'
    }
})

obj.a           //run get
  • set
/**
 * set,拦截赋值操作
 */
//四种赋值: [] . Object.create(proxy) Reflect.set
var obj = {}
var p = new Proxy(obj, {
    set() {
        console.log('run set')
        return Reflect.set(...arguments)        //赋值
    }
})
Reflect.set(p, 'a', 1)      //run set
p.a = 2                     //run set
p['a'] = 3                  //run set
Object.create(p).a = 1      //run set
//set内Reflect操作
var obj = {}
var p = new Proxy(obj, {
    set(target, property, value, receiver) {
        return Reflect.set(obj, property, value)        //赋值
        //死循环,RangeError: Maximum call stack size exceeded
        // return Reflect.set(p, property, value)
    }
})

p.a = 1        //1
p               //{ a: 1 }
obj             //{ a: 1 }
  • has
/**
 * has,针对 in 操作符的代理方法
 */
//拦截:属性查询,继承属性查询,with检查,Reflect.has
var p = new Proxy({ a: 1, _a: 2 }, {
    has(target, prop) {
        if (prop[0] == '_') {
            return false
        }
        return Reflect.has(target, prop);
    }
});

'a' in p                    //true
'_a' in p                   //false
'a' in Object.create(p)     //true
'_a' in Object.create(p)    //false
Reflect.has(p, 'a')          //true
Reflect.has(p, '_a')         //false
  • deleteProperty
/**
 * deleteProperty,拦截 delete 操作
 */
//操作:delete 或 Reflect.deleteProperty
var p = new Proxy({ a: 1 }, {
    deleteProperty: function (target, prop) {
        // console.log('run deleteProperty')
        return true;
    }
});

delete p.a;                         //true
p                                   //run deleteProperty    {a: 1}
Reflect.deleteProperty(p, 'a')      //true
p                                   //run deleteProperty    {a: 1}

//搭配Reflect.deleteProperty
var p = new Proxy({ a: 1 }, {
    deleteProperty: function (target, prop) {
        return Reflect.deleteProperty(target, prop);
    }
});

delete p.a;         //true
p                   //{}
  • defineProperty
/**
 * defineProperty,拦截对对象的 Object.defineProperty() 操作
 */
var p = new Proxy({}, {
    defineProperty(target, prop, descriptor) {
        return Reflect.defineProperty(target, prop, descriptor);
    }
});

Object.defineProperty(p, 'name', {          //{ value: 'proxy' }
    value: 'proxy',
    type: 'custom'          //忽略
});
p                           //{name: "proxy"}
  • apply
/**
 * apply,拦截函数的调用
 */
//参数
var add = (a, b) => a + b
var p = new Proxy(add, {
    apply(target, thisArg, argumentsList) {
        target === add          //true
        thisArg === p           //true
        argumentsList           //[1,2]
    }
})
p.call(p, 1, 2)
//三种调用:proxy(),Function.prototype.apply/call,Reflect.apply
var p = new Proxy((a, b) => a + 10 * b, {
    apply(target, thisArg, argumentsList) {
        return target(...argumentsList)
    }
})

p(1, 2)                                 //21
Reflect.apply(p, null, [1, 2])          //21
p.call(null, 1, 2)                      //21
p.apply(null, [1, 2])                   //21
  • construct
/**
 * construct,拦截new 操作符
 * 目标对象具有[[Construct]]内部方法
 * 返回值:必须对象
 */
//拦截操作:new proxy(...args)、Reflect.construct()
var p = new Proxy(function () { }, {
    construct: function (target, argumentsList, newTarget) {
        // console.log('run construct')
        return { a: 1 }
    }
});
new p()                     //run construct
Reflect.construct(p, [])    //run construct

//参数
var p = new Proxy(function () { }, {
    construct: function (target, argumentsList, newTarget) {
        argumentsList                   //[1]
        // console.log(newTarget == p)     //true
        return {}
    }
});

new p(1)

Proxy.revocable

  • 返回一个可取消的 Proxy 实例
//返回一个可取消的 Proxy 实例
var { proxy: p, revoke } = Proxy.revocable({}, {})
p.a = 1
p.a                 //1
// revoke()
p.a             //TypeError

this问题

//不能直接代理一些需要 this 的对象
//原生对象的内部属性
var target = new Date('2020-01-01')
var handler = {
    get(target, prop) {
        if (prop == 'getDate') {
            return target.getDate.bind(target)
        } else {
            return Reflect.get(target, prop)
        }
    }
}

var proxy = new Proxy(target, handler)
proxy.getDate()                 //1
// proxy.getMonth()                //报错

应用

  • 响应式数据
//数据响应式
var watch = (obj, event1, event2) => {
    return new Proxy(obj, {
        //手机依赖
        get(target, property) {
            event1(target, property)
            return Reflect.get(...arguments)
        },
        //更新
        set(target, property, value) {
            event2(target, property, value)
            return Reflect.set(...arguments)
        }
    })
}

var p = watch({ a: 1 },
    (target, property) => {
        console.log(`get: ${property}=${target[property]}`)
    },
    (target, property, value) => {
        console.log(`set: ${property}${target[property]}->${value}`)
    })
p.a = 2
p.a
  • 数据校验
//数据校验
function validator(target, validator) {
    return new Proxy(target, {
        set(target, key, value, receiver) {
            if (target.hasOwnProperty(key)) {
                if (validator[key](value)) {
                    return Reflect.set(target, key, value, receiver)
                } else {
                    throw Error(`不能设置${key}${value}`)
                }
            } else {
                throw Error(`${key}不存在`)
            }
        }
    })
}

class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
        return validator(this, {
            name(val) {
                return typeof val === 'string'
            },
            age(val) {
                return typeof val === 'number' && val > 18
            }
        })
    }
}

var person = new Person('knyel', 30)
person
person.name = 'lk'
// person.age = 12     //报错  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值