理解JavaScript中的Proxy 与 Reflection API

 更新时间:2020年09月21日 11:55:21   作者:Starryland  
这篇文章主要介绍了JavaScript中的Proxy 与 Reflection API的相关资料,帮助大家更好的理解和学习JavaScript,感兴趣的朋友可以了解下

一、创建 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:新属性对应的 key
  • value:新属性对应的 value
  • receiver:通常为 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的资料请关注脚本之家其它相关文章!

相关文章

  • 自定义排序算法在JavaScript中的应用小结

    自定义排序算法在JavaScript中的应用小结

    这篇文章主要介绍了自定义排序算法在JavaScript中的应用,通过自定义排序函数,我们能够精确控制数组元素的排序逻辑,从而满足各种复杂的应用场景,需要的朋友可以参考下
    2024-12-12
  • 用RadioButten或CheckBox实现div的显示与隐藏

    用RadioButten或CheckBox实现div的显示与隐藏

    用RadioButten(或CheckBox)实现div的显示与隐藏,当选择“女”时,显示“美女、才女”;当选择“男”时隐藏,具体实现如下,感兴趣的朋友可以参考下
    2013-09-09
  • QML实现圆环颜色选择器

    QML实现圆环颜色选择器

    这篇文章主要为大家详细介绍了QML实现圆环颜色选择器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • 使用script的src实现跨域和类似ajax效果

    使用script的src实现跨域和类似ajax效果

    在解决js的跨域问题的时候, 有多种方式, 其中有一种是利用script标签的src属性,因为这个属性是不受域名限制的,我们可以直接让src的这个链接指向跨域网站的一个接口, 这个接口返回的是js代码或者json格式数据, 从而实现跨域获取数据。
    2014-11-11
  • JavaScript中DOM和BOM原理详析

    JavaScript中DOM和BOM原理详析

    这篇文章主要介绍了JavaScript中DOM和BOM原理详析,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • 基于Cesium实现卫星在轨绕行动画

    基于Cesium实现卫星在轨绕行动画

    这篇文章主要为大家详细介绍了如何利用Cesium实现卫星在轨绕行动画,文中的示例代码讲解详细,对我们了解Cesium有一定的帮助,感兴趣的可以尝试一下
    2022-06-06
  • 封装一个公用Echarts图表组件的3种模板代码示例

    封装一个公用Echarts图表组件的3种模板代码示例

    这篇文章主要给大家介绍了关于封装一个公用Echarts图表组件的3种模板,定义图表公共样式是为了统一同一网站各页面图表的基础样式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-02-02
  • 通过JS判断联网类型和连接状态的实现代码

    通过JS判断联网类型和连接状态的实现代码

    这篇文章主要介绍了通过JS判断联网类型和连接状态的实现代码,需要的朋友可以参考下
    2015-04-04
  • JavaScript Window浏览器对象模型原理解析

    JavaScript Window浏览器对象模型原理解析

    这篇文章主要介绍了JavaScript Window浏览器对象模型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • JS实现小星星特效

    JS实现小星星特效

    这篇文章主要为大家详细介绍了JS实现小星星特效,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12

最新评论