ES6-Proxy

前言

Proxy, 也就是代理。设计模式中有一种叫做代理模式,可以用来实现AOP,拦截器。后端经常会用到。

那什么是代理模式,这样说吧。快到5.20了你想追个妹子,可惜没她联系方式,刚好你朋友认识她,你就请你的朋友代理你,捎信给她,表诉你的爱慕之情。就有点像读书那会的送情书。

代理在生活中很常见,董事长和助理之间是代理关系,你的领导和你之间也是代理,领导安排活,你就干。领导 ~ 你 ~ 活,这三者之间,你就是属于代理人,领导只管安排,然后你处理好,把结果给他看。是不是很简单?

 

开始进入正题

ES6 原生提供了 Proxy API , 用来生成 Proxy 实例。

那 Proxy 在前端有什么用处呢

①、拦截和监视外部对对象的访问

②、降低函数或类的复杂度

③、在复杂操作前对操作进行校验或对所需资源进行管理

运用

一、如何使用 Proxy 

let proxy = new Proxy(target, handler);

target 参数表示需要拦截的目标对象。

handler 参数是一个对象,用来定制拦截行为。

handler 支持 13 种拦截行为,如下:

get(target, property, receiver)     //拦截对象属性的读取
set(target, property, value, receiver)    //拦截对象属性的设置
has(target, property)    // 拦截 property in target 的操作,返回布尔值
deleteProperty(target, property) // 拦截 delete target[property] 的操作,返回布尔值
apply(target, context, args)   //拦截 Proxy实例作为函数调用的操作
construct(target, args)  // 拦截 Proxy 实例作为构造函数调用的操作
ownKeys(target)

//以下方法,分别拦截 Object对象 下对应的操作
//如 definedProperty 拦截 Object.defineProperty(proxy) 操作。
getOwnPropertyDescriptor(target, propKey)
defineProperty(target, propKey, propDesc)
preventExtensions(target)
isExtensible(target)
getPrototypeOf(target)
setPrototypeOf(target, proto)

Proxy 功能强大,我们经常用到的是它的 get, set 方法。

举个栗子,拦截某个对象的属性读写。

let obj = {
    name: 'jk',
    age: 25
}

let handler = {
    get(target, property, receiver) {
        let value = target[property];
        console.log(`get ${property} value: ${value}`);
        return value;
    },
    set(target, property, value, receiver) {
        console.log(`set ${property} value: ${value}`)
    }
}

let proxy = new Proxy(obj, handler);

proxy.name 
// get name value: jk
// jk

proxy.age = 26;
// set name value: 26
// 26

二、Proxy的用处

有的童鞋就会问,Proxy 到底有什么用处呢? 当然有用了,下面介绍下我能想到的用处。

① 实现 AOP

运用 Proxy 的 apply 方法。

我们有时候希望 在函数执行之前,先运行某函数,函数执行之后,再运行某函数。

先定义几个函数,后面会用到。

const log = (...args) => console.log(...args);

const test = () => log('test'); 
const beforeTest = () => log('beforeTest'); 
const afterTest = () => log('afterTest'); 

最基本的实现:

const testBetter = (cur, before, after) => {    
    before();
    cur();
    after();
}

testBetter(test, beforeTest, afterTest);

说实话,我觉得上面的代码就可以了,没什么不好。。。。。

当然也有其他的方法:

之前没有 Proxy 的做法是利用 闭包实现一个装饰器模式,(ES7已实现 Decorator),如下:

Function.prototype.before = function(beforefn) {
    let _self = this;  //存储 当前函数
    return function() {
        beforefn.apply(_self, arguments);
        return _self.apply(this, arguments);   
    }
}

Function.prototype.after = function(afterfn) {
    let _self = this; //存储 当前函数
    return function() {
        var ret = _self.apply(this, arguments);
        afterfn.apply(this, arguments);
        return ret; 
    }
}

const testBetter = test.before(beforeTest).after(afterTest);

testBetter();
// beforeTest
// test
// afterTest

现在,我们有了 Proxy, 就可以更方便了。可以运用 Proxy 的 apply 方法来实现。

const createProxy = (target, handler) => new Proxy(target, handler);
const createAop = (current, before, after) => {
    return createProxy(current, {
        apply(target, context, args) {
            before.call(context);
            Reflect.apply(...arguments);  // target.apply(context, args);
            after.call(context)
        }
    })
}
const testProxy = createAop(test, beforeTest, afterTest);
testProxy();
// beforeTest
// test
// afterTest

我们可以用 boforeTest 和 afterTest 来打印一些我们调试所需要的信息,不就实现了一个简单的日志功能吗。

②、我们也可以用 Proxy 的 get 来过滤数据。

let grade = {
    age: [4, 5, , undefined, 6, 7, ,null, 8, , 9, 10]
}

//去除undefined 和 null
let filterArr = (arr) => arr.filter(item => item !== undefined && item !== null);

let proxy = new Proxy(grade, {
    get(target, property, receiver) {
        let value = target[property];
        if ( Array.isArray(value) ) {
            return Reflect.apply(filterArr, window, [value]);
        }
    }
})

proxy.age;
// [4, 5, 6, 7, 8, 9, 10]

还可以实现其他的功能:拦截,数据校验,私有属性等等。

三、Proxy 如何取消。

Proxy.revocable方法返回一个可取消的 Proxy 实例。

let {proxy, revoke} = Proxy.revocable(target, handler);

 

文章只是叙述了 Proxy 的冰山一角,更多内容请移步我的参考链接。

今天先写到这里,如有错误之处,还望指出。谢谢。

 

参考

http://es6.ruanyifeng.com/#docs/proxy

https://www.w3cplus.com/javascript/use-cases-for-es6-proxies.html

曾探-JavaScript设计模式与开发实践,P48

转载于:https://www.cnblogs.com/jkCaptain/p/9017952.html

ES6 Reflect 和 Proxy》是一篇介绍 JavaScript ES6 中两个重要特性的文章。Reflect 和 Proxy 都是 ES6 新增的全局对象,它们提供了一些高级的操作方法,使得对对象的操作更加灵活和强大。 ### Reflect Reflect 是一个内置的对象,它提供了一系列静态方法,这些方法与某些 Object 的方法功能相同,但有一些改进和增强。Reflect 的主要目的是让 Object 的操作变得更加一致和可预测。 #### 主要特点: 1. **一致性**:Reflect 的方法与那些直接在 Object 上定义的方法行为一致。 2. **函数式编程**:Reflect 的方法都是函数式的,这使得它们可以很容易地被传递和使用。 3. **更好的错误处理**:Reflect 的方法会抛出更明确的错误信息,便于调试。 #### 常用方法: - `Reflect.get(target, propertyKey[, receiver])`:获取对象的属性值。 - `Reflect.set(target, propertyKey, value[, receiver])`:设置对象的属性值。 - `Reflect.has(target, propertyKey)`:判断对象是否有某个属性。 - `Reflect.deleteProperty(target, propertyKey)`:删除对象的属性。 - `Reflect.apply(target, thisArgument, argumentsList)`:调用一个函数。 - `Reflect.construct(target, argumentsList[, newTarget])`:使用构造函数创建一个实例。 ### Proxy Proxy 是另一个重要的 ES6 特性,它允许你创建一个代理对象,用于拦截和自定义基本操作(如属性查找、赋值、枚举、函数调用等)。通过 Proxy,你可以实现一些高级的功能,比如数据绑定、日志记录、性能监控等。 #### 主要特点: 1. **拦截操作**:Proxy 可以拦截并自定义各种操作,包括属性访问、赋值、枚举、函数调用等。 2. **灵活性**:通过 Proxy,你可以在运行时动态地改变对象的行为。 3. **安全性**:Proxy 可以用来创建安全的代理对象,防止未经授权的访问和修改。 #### 基本用法: ```javascript let target = { message: 'Hello, world!' }; let handler = { get: function(obj, prop) { return prop in obj ? obj[prop] : 'Property not found'; } }; let proxy = new Proxy(target, handler); console.log(proxy.message); // 输出: Hello, world! console.log(proxy.nonExistentProperty); // 输出: Property not found ``` ### 总结 Reflect 和 ProxyES6 中非常强大的特性,它们为 JavaScript 提供了更多的灵活性和控制力。通过学习和掌握这两个特性,你可以编写出更加高效、安全和可维护的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值