We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
使用proxy,你可以把老虎伪装成猫的外表,这有几个例子,希望能让你感受到proxy的威力。 proxy 用来定义自定义的基本操作行为,比如查找、赋值、枚举性、函数调用等。
proxy接受一个待代理目标对象和一些包含元操作的对象,为待代理目标创建一个‘屏障’,并拦截所有操作,重定向到自定义的元操作对象上。
proxy通过new Proxy来创建,接受两个参数:
new Proxy
闲话少说,直接看例子。
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.x、target[x]、Reflect.get(target, 'x')都会返回233 当然,代理get仅仅是其中一种操作,还有: - get - set - has - apply - construct - ownKeys - deleteProperty - defineProperty - isExtensible - preventExtensions - getPrototypeOf - setPrototypeOf - getOwnPropertyDescriptor
taget.x
target[x]
Reflect.get(target, 'x')
在其他语言中,如果访问对象中没有的属性,默认会返回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中也可以实现。
Array.lastItem
const negativeArray = els => new Proxy(els, { get: (target, k) => Reflect.get(target, +k < 0 ? String(target.length + +k) : k) })
需要注意的一点是,get操作会字符串化所有的操作,所以我们需要转换成number在进行操作, 这个运用也是negative-array的原理
negative-array
js未能实现私有属性,尽管之后引入了Symbol去设置独一无二的属性,但是这个被后来的Object.getOwnPropertySumbols淡化了 长期以来,人们使用下划线_来表示属性的私有,这意味着不运行外部操作该属性。不过,proxy提供了一种更好的方法来实现类似的私有属性
Symbol
Object.getOwnPropertySumbols
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可以让对象变得只读,但是我们可以提供更好的方法,让开发者在操作属性的时候获取明确的提示
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用来判断指定的属性是否指定对象或者对象的原型链上,这种行为可以很优雅的被重载,比如创建一个用于判断目标数字是否在制定范围内的代理
handler.has
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;
util.types.isProxy
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Proxy
使用proxy,你可以把老虎伪装成猫的外表,这有几个例子,希望能让你感受到proxy的威力。
proxy 用来定义自定义的基本操作行为,比如查找、赋值、枚举性、函数调用等。
proxy接受一个待代理目标对象和一些包含元操作的对象,为待代理目标创建一个‘屏障’,并拦截所有操作,重定向到自定义的元操作对象上。
proxy通过
new Proxy
来创建,接受两个参数:闲话少说,直接看例子。
最简单的只代理一个方功能,在这个例子里,我们让
get
操作,永远返回一个固定的值无论你
taget.x
、target[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解决这个问题
建议根据不同类型返回不同的默认值,Number => 0 String => '' Object => {} Array => []等等
数组负索引取值
js中,获取数组的最后一个元素是相对麻烦的,容易出错的。这就是为什么TC39提案定义一个方便的属性,
Array.lastItem
去获取最后一个元素。其他语言比如python,和ruby提供了访问数组最后一个元素的方法,例如使用arr[-1]代替arr[arr.length - 1]
不过,我们有proxy,负索引在js中也可以实现。
需要注意的一点是,get操作会字符串化所有的操作,所以我们需要转换成number在进行操作,
这个运用也是
negative-array
的原理隐藏属性
js未能实现私有属性,尽管之后引入了
Symbol
去设置独一无二的属性,但是这个被后来的Object.getOwnPropertySumbols
淡化了长期以来,人们使用下划线_来表示属性的私有,这意味着不运行外部操作该属性。不过,proxy提供了一种更好的方法来实现类似的私有属性
结果
如果你打印该proxy代理对象,会在控制台看到,不过无所谓。
缓存失效
服务端和客户端同步一个状态可能会出现问题,这很常见,在整个操作周期内,数据都有可能被改变,并且很难去掌握需要重新同步的时机。
proxy提供了一种新的办法,可以让属性在必要的时候失效,所有的访问操作,都会被检查判断,是否返回缓存还是进行其他行为的响应。
上面的功能很简单,他在一定时间内正常返回访问的属性,当超出ttl时间后,会返回undefined。
上面的例子会输出undefined在十秒后,更多的骚操作还请自行斟酌。
只读
尽管
Object.freeze
可以让对象变得只读,但是我们可以提供更好的方法,让开发者在操作属性的时候获取明确的提示枚举
结合上面的只读方法
我们得到了一个对象,如果你访问不存在的属性,不会得到undefined,而是抛出一个指向异常错误,折让调试变得更方便。
这也是一个代理代理的例子,需要保证被代理的代理是一个合法的代理对象,这个有助于混合一些复杂的功能。
重载操作符
最神奇的可能就是重载某些操作符了,比如使用
handler.has
重载in
。in用来判断指定的属性是否指定对象或者对象的原型链上,这种行为可以很优雅的被重载,比如创建一个用于判断目标数字是否在制定范围内的代理
上面的例子,虽然不是什么复杂的操作,也没有解决什么复杂的问题,但是这种清晰,可读,可复用的方式相信也是值得推崇的。
当然除了in操作符,还有delete 和 new;
其他
util.types.isProxy
来判断The text was updated successfully, but these errors were encountered: