Proxy

使用proxy,你可以把老虎伪装成猫的外表,这有几个例子,希望能让你感受到proxy的威力。

proxy 用来定义自定义的基本操作行为,比如查找、赋值、枚举性、函数调用等。

proxy接受一个待代理目标对象和一些包含元操作的对象,为待代理目标创建一个‘屏障’,并拦截所有操作,重定向到自定义的元操作对象上。

proxy通过new Proxy来创建,接受两个参数:

  1. 待代理目标对象
  2. 元操作对象

闲话少说,直接看例子。

最简单的只代理一个方功能,在这个例子里,我们让get操作,永远返回一个固定的值

let target = {
name: 'fox',
age: 23
}
let handler = {
get: (obj, k) => 233
}
target = new Proxy(target, handler);
target.a // 233
target.b // 233
target.c // 233

无论你taget.xtarget[x]Reflect.get(target, 'x')都会返回233

当然,代理get仅仅是其中一种操作,还有:

- get

- set

- has

- apply

- construct

- ownKeys

- deleteProperty

- defineProperty

- isExtensible

- preventExtensions

- getPrototypeOf

- setPrototypeOf

- getOwnPropertyDescriptor

改变默认值为0

在其他语言中,如果访问对象中没有的属性,默认会返回0,这在某些场景下很有用,很方便,比如坐标系,一般来说z轴默认是0.

但是在js中,对象中不存在的key的默认值是undefined,而不是合法的初始值。

不过可以使用proxy解决这个问题

const defaultValueObj = (target, defaultValue) => new Proxy(target, {
get: (obj, k) => Reflect.has(obj, k) ? obj[k] : defaultValue
})

建议根据不同类型返回不同的默认值,Number => 0 String => '' Object => {} Array => []等等

数组负索引取值

js中,获取数组的最后一个元素是相对麻烦的,容易出错的。这就是为什么TC39提案定义一个方便的属性,Array.lastItem去获取最后一个元素。

其他语言比如python,和ruby提供了访问数组最后一个元素的方法,例如使用arr[-1]代替arr[arr.length - 1]

不过,我们有proxy,负索引在js中也可以实现。

const negativeArray = els => new Proxy(els, {
get: (target, k) => Reflect.get(target, +k < 0 ? String(target.length + +k) : k)
})

需要注意的一点是,get操作会字符串化所有的操作,所以我们需要转换成number在进行操作,

这个运用也是negative-array的原理

隐藏属性

js未能实现私有属性,尽管之后引入了Symbol去设置独一无二的属性,但是这个被后来的Object.getOwnPropertySumbols淡化了

长期以来,人们使用下划线_来表示属性的私有,这意味着不运行外部操作该属性。不过,proxy提供了一种更好的方法来实现类似的私有属性

const enablePrivate = (target, prefix = '_') => new Proxy(target, {
has: (obj, k) => (!k.startsWith(prefix) && k in obj),
ownKeys: (obj, k) => Reflece.ownKeys(obj).filter(k => (typeof k !== 'string' || !k.startsWith(prefix))),
get: (obj, k, rec) => (k in rec) ? obj[k] : undefined
})

结果

let userData = enablePrivate({
firstName: 'Tom',
mediumHandle: '@tbarrasso',
_favoriteRapper: 'Drake'
}) userData._favoriteRapper // undefined
('_favoriteRapper' in userData) // false
Object.keys(userData) // ['firstName', 'mediumHandle']

如果你打印该proxy代理对象,会在控制台看到,不过无所谓。

缓存失效

服务端和客户端同步一个状态可能会出现问题,这很常见,在整个操作周期内,数据都有可能被改变,并且很难去掌握需要重新同步的时机。

proxy提供了一种新的办法,可以让属性在必要的时候失效,所有的访问操作,都会被检查判断,是否返回缓存还是进行其他行为的响应。

const timeExpired = (target, ttl = 60) => {
const created_at = Date.now();
const isExpired = () => (Date.now - created_at) > ttl * 1000;
return new Proxy(tarvet, {
get: (target, k) => isExpired() ? undefined : Reflect.get(target, k);
})
}

上面的功能很简单,他在一定时间内正常返回访问的属性,当超出ttl时间后,会返回undefined。

let timeExpired = ephemeral({
balance: 14.93
}, 10) console.log(bankAccount.balance) // 14.93 setTimeout(() => {
console.log(bankAccount.balance) // undefined
}, 10 * 1000)

上面的例子会输出undefined在十秒后,更多的骚操作还请自行斟酌。

只读

尽管Object.freeze可以让对象变得只读,但是我们可以提供更好的方法,让开发者在操作属性的时候获取明确的提示

const nope = () => {
throw new Error('不能改变只读属性')
}
const read_only = (obj) => new Proxy(obj, {
set: nope,
defineProperty: nope,
deleteProperty: nope,
preentExtensions: nope,
setPrototypeOf: nope
});

枚举

结合上面的只读方法

const createEnum = (target) => read_only(new Proxy(target, {
get: (obj, k) = {
if (k in obj) {
return Reflect.get(obj, k)
}
throw new ReferenceError(`找不到属性${k}`)
}
}))

我们得到了一个对象,如果你访问不存在的属性,不会得到undefined,而是抛出一个指向异常错误,折让调试变得更方便。

这也是一个代理代理的例子,需要保证被代理的代理是一个合法的代理对象,这个有助于混合一些复杂的功能。

重载操作符

最神奇的可能就是重载某些操作符了,比如使用handler.has重载in

in用来判断指定的属性是否指定对象或者对象的原型链上,这种行为可以很优雅的被重载,比如创建一个用于判断目标数字是否在制定范围内的代理

const range = (min, max) => new Proxy(Object.create(null), {
has: (obj, k) => (+k > min && +k < max)
})
const X = 10.5
const nums = [1, 5, X, 50, 100] if (X in range(1, 100)) { // true
// ...
} nums.filter(n => n in range(1, 10)) // [1, 5]

上面的例子,虽然不是什么复杂的操作,也没有解决什么复杂的问题,但是这种清晰,可读,可复用的方式相信也是值得推崇的。

当然除了in操作符,还有delete 和 new;

其他

  • 兼容性一般,不过谷歌开发的proxy-polyfill目前已经支持get、set、apply、construct到ie9了
  • 目前浏览器没有办法判断对象是否被代理,不过在node版本10以上,可以使用util.types.isProxy来判断
  • proxy的第一个参数必须是对象,不能代理原始值
  • 性能,proxy的一个缺点就是性能,但是这个也因人/浏览器而异,不过,proxy绝对不适合用在性能关键点的代码上,当然,你可以衡量proxy带来的遍历和可能损耗的性能,进行合理的中和,来达到最佳的开发体验和用户体验

es6 proxy浅析的更多相关文章

  1. ES6 Proxy 性能之我见

    ES6 Proxy 性能之我见 本文翻译自https://thecodebarbarian.com/thoughts-on-es6-proxies-performance Proxy是ES6的一个强力 ...

  2. Vue3.0 响应式数据原理:ES6 Proxy

    Vue3.0 开始用 Proxy 代替 Object.defineProperty了,这篇文章结合实例教你如何使用Proxy 本篇文章同时收录[前端知识点]中,链接直达 阅读本文您将收获 JavaSc ...

  3. ES6 Proxy和Reflect(下)

    construct() construct方法用于拦截new命令. var handler = { construct (target, args) { return new target(...ar ...

  4. ES6 Proxy和Reflect (上)

    Proxy概述 Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种"元编程"(meta programming),即对编程语言进行编程. Proxy可以理 ...

  5. es6 proxy代理

    es6 新增构造函数 Proxy Proxy 构造函数,可以使用new 去创建,可以往里面插入两个参数,都是对象 let target = {} let handler = {} let proxy ...

  6. es6 Proxy

    proxy在语言层面去操作一个对象 var user={}; user.fname='Bob'; user.lname="Wood"; user.fullName= functio ...

  7. ES6 Proxy的应用场景

    一.相关API Proxy Reflect 二.Proxy应用场景 1.数据校验 表单提交的时候做数据校验,例如年龄是不是满足条件,数据类型是不是满足要求等等,这场场景非常适合使用Proxy. 下面展 ...

  8. es6 Proxy对象详解

    Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改.这个词的原理为代理,在这里可以表示 ...

  9. 新的知识点来了-ES6 Proxy代理 和 去银行存款有什么关系?

    ES给开发者提供了一个新特性:Proxy,就是代理的意思.也就是我们这一节要介绍的知识点. 以前,ATM还没有那么流行的时候(暴露年纪),我们去银行存款或者取款的时候,需要在柜台前排队,等柜台工作人员 ...

随机推荐

  1. SpringBoot 常用注解简单总结

    终于有时间对刚学的SpringBoot注解总结一下了,Annotation(注解)是JDK 5.0之后及以后版本引入的,这个时候需要在Spring中申明一个Bean,只能通过xml的方式,非常繁琐.但 ...

  2. .net里面<app.config>中value值不能填写特殊符号问题

    配置app.config或web.config的时候,经常要填写value值, 但是value值不能包含特殊字符,需要转义, 分享一下转义字符 App.config 实际上是 xml 文件,在标准 x ...

  3. VIM编辑器的常用命令及使用!

    在热门Linux操作系统中都会默认安装一款超好用的文本编辑器——名字叫“vim”,vim是vi编辑器的升级版. Vim能够得到这么多厂商与用户的认可,原因就是在Vim编辑器中有三种模式——命令模式.末 ...

  4. 自己实现 aop 和 spring aop

    上文说到,我们可以在 BeanPostProcessor 中对 bean 的初始化前化做手脚,当时也说了,我完全可以生成一个代理类丢回去. 代理类肯定要为用户做一些事情,不可能像学设计模式的时候创建个 ...

  5. 手写jwt验证,实现java和node无缝切换

    前言 前端时间和我朋友写了一个简易用户管理后台,功能其实很简单,涉及到的技术栈有:vue+elementUI,java+spring MVC以及node+egg,数据库用的mysql,简单方便. 一开 ...

  6. 腾讯正式开源图计算框架Plato,十亿级节点图计算进入分钟级时代

    腾讯开源再次迎来重磅项目,14日,腾讯正式宣布开源高性能图计算框架Plato,这是在短短一周之内,开源的第五个重大项目. 相对于目前全球范围内其它的图计算框架,Plato可满足十亿级节点的超大规模图计 ...

  7. 裸板中中断异常处理,linux中断异常处理 ,linux系统中断处理的API,中断处理函数的要求,内核中登记底半部的方式

    1.linux系统中的中断处理  1.0裸板中中断异常是如何处理的?     以s5p6818+按键为例          1)按键中断的触发        中断源级配置            管脚功 ...

  8. python Tesseract安装方法

    python Tesseract安装方法 EXE可执行文件地址:http://download.csdn.net/download/whatday/7740469:下载tesseract-ocr-se ...

  9. 直接引用MrAdvice.dll文件不能实现AOP拦截,教你1分钟解决这个问题

    直接引用MrAdvice.dll文件不能实现AOP拦截,教你1分钟解决这个问题.近日工作中,要实现一个功能,那就是业务层方法里面实现自动缓存.编写业务的C#开发人员只关注如何将业务代码编写正确就可以了 ...

  10. pat 1149 Dangerous Goods Packaging(25 分)

    1149 Dangerous Goods Packaging(25 分) When shipping goods with containers, we have to be careful not ...