一、创建 Proxy
let target = {} let proxy = new Proxy(target, {}) proxy.name = "proxy" console.log(proxy.name) // proxy console.log(target.name) // proxy target.name = "target" console.log(proxy.name) // target console.log(target.name) // target
在上面的例子中,由 Proxy
构造器创建的 proxy
对象会将自身的所有操作直接转发给 target
。
当 proxy.name
被赋值为 "proxy"
时,target
对象也会创建 name
属性并获得同样的值。实际上 proxy
对象本身并不创建和存储 name
属性,它只是转发对应的操作给 target
。
类似的,proxy.name
与 target.name
的值始终保持一致,因为它们实际上都指向了 target.name
。这也意味着给 target.name
赋予一个新的值时,该变化也会反映到 proxy.name
上。
使用 set Trap 验证属性
Proxy 允许开发者主动拦截本该转发给 target 对象的底层操作,这些拦截行为通过 trap
实现。每个 trap
都可以覆盖 JavaScript 对象的某些内置行为,即 proxy 允许通过 trap
拦截并修改指向 target 对象的操作。
假设需要创建一个新添加的属性值只能是数字类型的对象,就可以借助 set
trap 覆盖默认的赋值行为。代码如下:
let target = { name: "target" } let proxy = new Proxy(target, { set(trapTarget, key, value, receiver) { if (!trapTarget.hasOwnProperty(key)) { if (isNaN(value)) { throw new TypeError("New property must be a number.") } } return Reflect.set(trapTarget, key, value, receiver) } }) proxy.count = 1 console.log(proxy.count) // 1 console.log(target.count) // 1 proxy.name = "proxy" console.log(proxy.name) // proxy console.log(target.name) // proxy proxy.anotherName = "proxy" // TypeError: New property must be a number.
set trap 中的四个参数含义如下:
trapTarget
:接收新属性的对象(即 proxy 指向的 target)key
:新属性对应的 keyvalue
:新属性对应的 valuereceiver
:通常为 proxy 自身
Reflect.set()
是与 set
trap 相对应的原始方法,表示被覆盖前的默认的赋值行为。
使用 get Trap 令程序读取不存在属性时报错
JavaScript 在读取不存在的属性时并不会报错,而是返回 undefined
。
let target = {} console.log(target.name) // undefined
可以借助 get
trap 修改读取对象属性时的默认行为:
let proxy = new Proxy({}, { get(trapTarget, key, receiver) { if (!(key in receiver)) { throw new TypeError("Property " + key + " doesn't exist.") } return Reflect.get(trapTarget, key, receiver) } }) proxy.name = "proxy" console.log(proxy.name) // proxy console.log(proxy.nme) // TypeError: Property nme doesn't exist.
通过 deleteProperty Trap 防止删除属性
JavaScript 中使用 delete
操作符删除对象的属性:
let target = { name: "target", value: 42 } Object.defineProperty(target, "name", { configurable: false }) console.log("value" in target) // true let result1 = delete target.value console.log(result1) // true console.log("value" in target) // false let result2 = delete target.name console.log(result2) // false console.log("name" in target) // true
使用 deleteProxy Trap 防止属性被意外删除:
let target = { name: "target", value: 42 } let proxy = new Proxy(target, { deleteProperty(trapTarget, key) { if (key === "value") { return false } else { return Reflect.deleteProperty(trapTarget, key) } } }) console.log("value" in proxy) // true let result1 = delete proxy.value console.log(result1) // false console.log("value" in proxy) // true let result2 = delete proxy.name console.log(result2) // true console.log("name" in proxy) // false
二、Proxy 的现实应用
logging
function makeLoggable(target) { return new Proxy(target, { get: (target, property) => { console.log("Reading " + property) return target[property] }, set: (target, property, value) => { console.log("Writing value " + value + " to " + property) target[property] = value } }) } let ninja = { name: "Yoshi" } ninja = makeLoggable(ninja) console.log(ninja.name) ninja.weapon = "sword" // Reading name // Yoshi // Writing value sword to weapon
性能测试
function isPrime(number) { if (number < 2) { return false } for (let i = 2; i < number; i++) { if (number % i === 0) { return false } } return true } isPrime = new Proxy(isPrime, { apply: (target, thisArg, args) => { console.time("isPrime") const result = target.apply(thisArg, args) console.timeEnd("isPrime") return result } }) console.log(isPrime(1358765377)) // isPrime: 6815.107ms // true
自动添加属性
function Folder() { return new Proxy({}, { get: (target, property) => { console.log("Reading " + property) if(!(property in target)) { target[property] = new Folder() } return target[property] } }) } const rootFolder = new Folder() rootFolder.ninjasDir.firstNinjaDir.ninjaFile = "yoshi.txt" // Reading ninjasDir // Reading firstNinjaDir console.log(rootFolder.ninjasDir.firstNinjaDir.ninjaFile) // Reading ninjasDir // Reading firstNinjaDir // Reading ninjaFile // yoshi.txt
参考资料
https://leanpub.com/understandinges6
https://www.manning.com/books/secrets-of-the-javascript-ninja-second-edition
以上就是理解JavaScript中的Proxy 与 Reflection API的详细内容,更多关于JavaScript中的Proxy 与 Reflection API的资料请关注其它相关文章!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]