ES2015 Proxy代理对象与Reflect反射对象

harmony-reflect:ES5垫片(用于ES6反射和代理对象) 这是ECMAScript 6和对象的填充。 这个库做两件事: 它定义了一个兼容ES6的Reflect全局对象,该对象导出ECMAScript 6反射API。 如果和声时代(ES6之前的版本) Proxy支持可用,它将修补Proxy以使其与。 2016年7月更新:所有主要浏览器和node.js的最新版本现在都与Reflect和Proxy对象。 如果您希望旧版本的浏览器或node.js <v6.0.0版本上的ES6 Reflect支持,或者想要node.js <v6.0.0版本上的ES6 Proxy支持,则此垫片非常有用。 2016年5月更新:最近发布的包括对ES2015 Proxies和Reflect的本地支持,使该库对于嵌入V8 4.9或更高版本(例如Chrome 49和Node v6.0)的环境已过时。 节点v5.10.x或更低版本仍需要此polyfill才能获得适当的ES6代 立即下载

Proxy 代理对象

如果想要监视某个对象中属性的读写,可以使用 ECMAScript2015 之前的 Object.defineProperty() 方法为对象添加属性,这样的话就可以监测到对象属性的读写过程。这种方法应用的非常广泛,在 Vue3.0 之前的版本就是使用这样的方法来实现数据响应,从而完成双向数据绑定。

在 ECMAScript2015 当中设计了 Proxy 类型,它就是专门为对象设置访问代理器的。如果你不能理解什么是代理的话,你可以把它想象成门卫。也就是说,无论你是从里面拿东西还是放东西,都需要经过这样的一个代理。通过 Proxy 就可以轻松地监视到对象属性的读写过程。相对于 Object.defineProperty() 方法,Proxy 的功能更为强大,使用起来也更为方便。

接下来,就来看看 Proxy 的具体用法。首先,通过字面量方式来定义一个 person 对象。如下代码所示:

const person = {
  name: '前端课湛',
  age: 20
}

然后,通过 new Proxy() 方式为 person 对象创建一个代理对象。如下代码所示:

const personProxy = new Proxy(person, {
  get() {},
  set() {}
})

在上述代码中,Proxy 构造函数中接收了两个参数,第一个参数就是代理的目标对象,第二个参数也是一个对象,可以称之为代理的处理对象。

这个代理的处理对象中的 get() 方法可以用来监视属性的访问,set() 方法可以用来监视属性的设置。

接下来,先看 get() 方法,这个方法可以接收 target 和 property 两个参数,这个方法的返回值是作为外部访问这个属性所得到的结果。如下代码所示:

const personProxy = new Proxy(person, {
  get(target, property) {
    console.log(target, property)
    return 100
  },
  set() {}
})

console.log(personProxy.name)

上述代码的运行结果如下:

{ name: '前端课湛', age: 20 } name
100

从打印的结果可以看到,这时的 get() 方法已经监听到了属性的读取。其中 target 参数指的是代理的目标对象,property 参数指的是外部访问对象的属性名,而返回值就是访问属性之后所得到的结果。

get() 方法内部正常的逻辑应该是先来判断代理目标对象当中是否存在这样一个属性,如下代码所示:

const personProxy = new Proxy(person, {
  get(target, property) {
    return property in target ? target[property] : undefined
  },
  set() {}
})

console.log(personProxy.name)
console.log(personProxy.xxx)

如果访问的属性存在的话,则返回该属性的值;如果不存在的话,则返回 undefined 或者提供的默认值。

然后,再来看一下 set() 方法,这个方法可以接收 target、property 和 value 三个参数。如下代码所示:

const personProxy = new Proxy(person, {
  get() {},
  set(target, property, value) {
    console.log(target, property, value)
  }
})

personProxy.gender = true

上述代码的运行结果如下:

{ name: '前端课湛', age: 20 } gender true

从打印结果可以看到,target 参数依旧表示代理的目标对象,property 参数表示设置的属性名,而 value 参数就是设置的属性值。

set() 方法内部正常的逻辑应该是为代理的目标对象设置对应的属性。如下代码所示:

const personProxy = new Proxy(person, {
  get() {},
  set(target, property, value) {
    if (property === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError(`${value} is not an integer.`)
      }
    }
    target[property] = value
  }
})

personProxy.age = 'hehehe'

这里的 set() 方法来判断设置的属性名是否为 age,如果是的话必须是整数,否则就报错。通过 personProxy 代理对象设置 age 属性值为 hehehe。运行的结果如下:

proxy.js:53
        throw new TypeError(`${value} is not an integer.`)
        ^

TypeError: hehehe is not an integer.
    at Object.set (proxy.js:53:15)
    at Object.<anonymous> (proxy.js:60:17)
    at Module._compile (internal/modules/cjs/loader.js:1201:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1221:10)
    at Module.load (internal/modules/cjs/loader.js:1050:32)
    at Function.Module._load (internal/modules/cjs/loader.js:938:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47

以上就是 Proxy 的一些基本用法,以后 Proxy 会越用越多,比如 Vue3.0 开始就已经使用 Proxy 来实现内部的数据响应。

Proxy 的优势

了解了 Proxy 的基本用法过后,接下来再深入探索一下相比于 Object.defineProperty() 来讲 Proxy 到底有哪些优势。

监听对象的更多操作

首先,最明显的优势在于 Proxy 更为强大一些。这个强大在于 Object.defineProperty() 只能监视属性的读写,而 Proxy 能够监视到 Object.defineProperty() 监视不到的更多对象的操作,比如 Delete 操作、调用对象的方法等等。如下代码所示:

const person = {
  name: '前端课湛',
  age: 20
}

const personProxy = new Proxy(person, {
  deleteProperty(target, property) {
    console.log(`delete ${property}`)
    delete target[property]
  }
})

delete personProxy.age
console.log(person)

上述代码为 person 对象创建了一个代理对象,并且通过代理对象的 deleteProperty() 方法监听 person 对象属性的删除操作。

上述代码的运行结果如下:

delete age
{ name: '前端课湛' }

从运行结果可以看到,Proxy 成功地监听到 Delete 操作。

Proxy 除了可以监视到对象的 Delete 操作以外,还有很多其他操作。如下表所示:

handler 方法触发方式
get读取某个属性
set写入某个属性
hasin 操作符
deletePropertydelete 操作符
getPropertyObject.getPropertyOf()
setPropertyObject.setPropertyOf()
isExtensibleObject.isExtensible()
preventExtensionsObject.preventExtensions()
getOwnProperyDescriptorObject.getOwnPropertyDescriptor()
definePropertyObject.defineProperty()
ownKeysObject.keys()、Object.getOwnPropertyName()、Object.getOwnPropertySymbols()
apply调用一个函数
construct通过 new 调用一个函数

更好地支持数组的监听

其次,Proxy 相比于 Object.defineProperty() 可以更好地支持数组对象的监视。以往想要通过 Object.defineProperty() 监视数组对象的操作,最常见的一种方式就是通过重写数组的操作方法,这也是 Vue 所使用的方式。大体的思路就是通过自定义的方法去覆盖数组原型对象上的原有方法,以此来劫持对应方法的调用过程。Proxy 又是如何监视数组对象的呢?如下代码所示:

const list = []

const listProxy = new Proxy(list, {
  set(target, property, value) {
    console.log('set: ', property, value)
    target[property] = value
    return true
  }
})

listProxy.push('前端课湛')

通过 Proxy 对象的 set() 方法监听数组的 push 操作,并且将指定成员添加到代理的目标数组中,最终返回 true 表示设置成功。

上述代码的运行结果如下:

set:  0 前端课湛
set:  length 1

从打印结果可以看到,这里的 0 就是数组的索引值,而前端课湛就是索引值对应的成员。也就是说,Proxy 内部可以通过数组的 push 操作来推算出来应该所处的索引值。对于数组的其他操作都是类似的,而这些操作如果通过 Object.defineProperty() 来实现的话就会特别麻烦。

非侵入的方式监听

最后,相比于 Object.defineProperty() 来讲 Proxy 的优势就是以非侵入的方式监管了对象的读写。也就是说,一个已经定义好的对象,不需要对对象本身去做任何的操作就可以监视到它内部成员的读写。如下代码所示:

const person = {
  name: '前端课湛',
  age: 20
}

const personProxy = new Proxy(person, {
  get(target, property) {
    console.log('get', property)
    return target[property]
  },
  set(target, property, value) {
    console.log('set', property, value)
    target[property] = value
  }
})

personProxy.name = '大前端'

console.log(personProxy.name)

而 Object.defineProperty() 方式要求需要通过特定的方式单独定义对象当中那些需要被监视的属性,那对于一个已经存在的对象想要监视它的属性需要去做很多额外的操作。如下代码所示:

const person = {
  name: '前端课湛',
  age: 20
}

Object.defineProperty(person, 'name', {
  get () {
    console.log('name 被访问')
    return person._name
  },
  set (value) {
    console.log('name 被设置')
    person._name = value
  }
})
Object.defineProperty(person, 'age', {
  get () {
    console.log('age 被访问')
    return person._age
  },
  set (value) {
    console.log('age 被设置')
    person._age = value
  }
})

person.name = '大前端'

console.log(person.name)

Reflect 反射对象

Reflect 是 ECMAScript2015 中提供的全新的内置对象,如果按照 Java 或者 C# 的说法,Reflect 属于一个静态类。也就是说,它不能通过 new Reflect() 构建一个实例对象,只能调用这个静态类提供的静态方法,比如 get() 等等。关于这一点应该不会太陌生,因为 JavaScript 语言中的 Math 也是这样的。

Reflect 内部封装了一系列对对象的底层操作,具体一共提供了 14 个静态方法,其中有一个被废弃了,所以目前还有 13 个。这 13 个方法的方法名与 Proxy 对象当中的处理对象的方法成员是完全一致的,其实 Reflect 的成员方法就是 Proxy 处理对象的那些方法的默认实现。如下代码所示:

const obj = {
  foo: '123',
  bar: '456'
}

const proxy = new Proxy(obj, {
  get(target, property) {
    console.log('watch logic~')

    return Reflect.get(target, property)
  }
})

console.log(proxy.foo)

当 Proxy 的处理对象当中并没有添加任何的成员时,Proxy 内部默认实现的逻辑就是调用了 Reflect 对象当中所对应的静态方法。这和上述代码当中直接将 Proxy 处理对象的 get() 方法直接调用 Reflect 对象的 get() 静态方法是一致的。

Reflect 对象的用法其实很简单,但是大多数人接触到这个对象的感觉就是为什么要有 Reflect 这样的一个对象?也就是说,Reflect 对象的价值到底体现在什么地方?Reflect 对象最大的意义就在于它提供了一套统一的用于操作对象的 API。

在这儿之前如果操作对象的话,有可能会使用 Object 对象上的一些方法,也有可能会使用比如 in 或者 delete 运算符,这些操作对新手来说实在是太乱了,并没有什么规律。如下代码所示:

const obj = {
  name: '前端课湛',
  age: 20
}

console.log('name' in obj)
console.log(delete obj['age'])
console.log(Object.keys(obj))

而 Reflect 对象就很好地解决了这样的一个问题,它统一了操作对象的方式。如下代码所示:

const obj = {
  name: '前端课湛',
  age: 20
}

console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))

需要注意的是,目前的情况是之前的用法还是可以使用的,但是 ECMAScript 官方希望经过一段时间的过渡过后,以后的标准当中就会把之前的方法废弃掉。

ES6 如何改变JS内置行为的代理与反射 代理(Proxy)可以拦截并改变 JS 引擎的底层操作,如数据读取、属性定义、函数构造等一系列操作。ES6 通过对这些底层内置对象的代理陷阱和反射函数,让开发者能进一步接近 JS 引擎的能力。 一、代理与反射的基本概念 什么是代理和反射呢? 代理是用来替代另一个对象(target),JS 通过new Proxy()创建一个目标对象的代理,该代理与该目标对象表面上可以被当作同一个对象来对待。 当目标对象上的进行一些特定的底层操作时,代理允许你拦截这些操作并且覆写它,而这原本只是 JS 引擎的内部能力。 如果你对些代理&反射的概念比较困惑的话,可以直接看后面的应用示例,最后再重新看这些定义 立即下载

相关推荐

Veritas NetBackup 10.1 Windows安装指南:从账户配置到完整部署

本文详细介绍了Veritas NetBackup 10.1在Windows系统上的完整安装流程,从账户配置到部署验证。重点讲解了创建专用服务账户、安装组件选择、许可证输入等关键步骤,并提供了常见问题排查和进阶配置建议,帮助用户顺利完成企业级备份解决方案的部署。

weixin_26765287的博客 453

ES6之Reflect学习

Reflect 是 es6 新出的API 下面列出来它的静态方法(13个) Reflect.apply(target, thisArg, args) Reflect.construct(target, args) Reflect.get(target, name, receiver) Reflect.set(target, name, value, receiver) Reflect.defineProperty(target, name, desc) Reflect.deleteProper

u012965830的专栏 230

Surface Go 2 变身 Linux 开发本:保姆级 Ubuntu 20.04 双系统安装与驱动配置全攻略

本文详细介绍了如何将 Surface Go 2 变身为高效的 Linux 开发本,涵盖 Ubuntu 20.04 双系统安装、专用内核配置、驱动优化等全流程。通过 linux-surface 内核安装和硬件驱动优化,确保 Surface Go 2 的触控、笔输入、摄像头等功能完美运行,适合开发者打造便携生产力工具。

weixin_30596165的博客 616

JavaScript学习之ES6 ES2015学记笔记(十一)-代理(Proxy)

说道Proxy就会想到各种编程中需要使用的代理服务器,在ES6新增这样一个新对象: var obj = new Proxy({}, { get: function (target, key, receiver) { console.log(`getting ${key}!`); return Reflect.get(target, key, receiv...

Three_ST的博客 801

VS2019集成AddressSanitizer:C++内存错误检测实战指南

在C++开发中,内存管理是核心挑战之一,涉及堆、栈和全局变量的分配与释放。其原理在于程序运行时对内存地址的访问必须严格遵循分配边界和生命周期规则,否则会导致缓冲区溢出、释放后使用等严重错误。这类问题的技术价值在于直接影响程序的稳定性、安全性和性能,是高质量软件必须攻克的基础难题。应用场景广泛,从嵌入式系统到大型服务器软件,都需要可靠的内存错误检测机制。AddressSanitizer(ASan)作为一种编译时插桩技术,通过影子内存和运行时检查,能精准定位堆缓冲区溢出、释放后使用等隐蔽错误。本文以Visual

weixin_34356310的博客 279

ISP算法:宽动态HDR

动态范围(Dynamic Range):在很多领域来表示某个变量的最大值和最小值的比值。在数字图像处理领域里,动态范围也被称为图像对比度,表示图像可以显示范围内,像素最大亮度值和最小亮度值的比值。 高动态范围图像(High Dynamic Range Image): 可以反映真实场景中高动态范围亮度信息图像。 高动态技术:能自动调整图像动态范围的一种技术。该技术是一种利用计算机高速运算产生高

a200800170331的专栏 1万+

ECMAScript6 (ES6、ES2015)新特性详解

ES6 新特性ES6 新特性 一ES6简介 二块级作用域绑定 1 let声明 2 const声明Constant Declarations 3 循环中的块级绑定 4 循环中的函数 三函数的新增特性 1 带默认参数的函数 2 默认参数对 arguments 对象的影响 3 默认参数表达式 Default Parameter Expressions 4 未命名参数问题 5 函数中的扩展

完善飞跃 2万+

【通信】多径衰落信道的matlab仿真

1 简介 2 部分代码 clearf_c=1e3; %carrier frequency(no modulation)time_1 = (linspace (0, 10, 1000)); %timesignal_in = sin (2 * pi *f_c* time_1); %sine wave plot (time_1, signal_in, 'b');grid on;

qq_59747472的博客 1382

ES6 (ES2015)总览

let 与 const 1.let与var的区别: let 是在代码块内有效,var 是在全局范围内有效 let 只能声明一次 var 可以声明多次 let 不存在变量提升,var 会变量提升 注:for 循环计数器很适合用 let ``` for (var i = 0; i < 10; i++) { setTimeout(function(){ console.log(i)...

qq_20535249的博客 374

论文阅读-Whisper语音识别(OpenAI)

Whisper 是一个自动语音识别(ASR,Automatic Speech Recognition)系统,OpenAI 通过从网络上收集了 68 万小时的多语言,其中11万小时覆盖96 种语言,12万小时的语言标号为英语,用多任务(multitask)监督数据对 Whisper 进行了训练。

一位不是很硕的鉴伪方向硕士 6366

【100%通过率】2024华为OD机试真题E卷 C++语言 实现【流浪地球】

流浪地球计划在赤道上均匀部署了N个转向发动机,按位置顺序编号为0~N-1。 1) 初始状态下所有的发动机都是未启动状态; 2) 发动机起动的方式分为“手动启动”和“关联启动”两种方式; 3) 如果在时刻1一个发动机被启动,下一个时刻2与之相邻的两个发动机就会被“关联启动”; 4) 如果准备启动某个发动机时,它已经被启动了,则什么都不用做; 5) 发动机0与发动机N-1是相邻; 地球联合政府准备挑选某些发动机在某些时刻进行“手动启动”,当然最终所有的发动机都会被启动。 哪些发动机最晚被启动呢?

MISAYAONE的博客 4210

ES2015 Proxy 对比 defineProperty

如果我们想监视某个对象的读写,我们可以使用ES5提供的defineProperty方法为对象添加属性,可以捕获到对象属性的读写过程。 defineProperty应用场景:在vue3.0 以前的版本,就是使用defineProperty实现了数据响应从而实现双向数据绑定。 因为Proxy比defineProperty,vue3.0 中使用的是Proxy 在ES2015中,全新设计了一个叫做Proxy 的类型,专门用来为对象设置访问代理器。 什么是代理呢? 通俗点解释:把代理想象成门卫,无论你是想出去还是

路遇惊喜 566

【从零开始学习SLAM】官方tf教程小海龟跟随程序

ros tf 进行坐标系之间转换的运算和发布

小秋 AI SLAM 入门实战教程 2033

为什么Proxy一定要配合Reflect使用?

引言EcmaScript 2015 中引入了 Proxy 代理[1] 与 Reflect 反射[2] 两个新的内置模块。我们可以利用 Proxy 和 Reflect 来实现对于对象的代理劫持操作,类似于 Es 5 中 Object.defineProperty\(\)[3]的效果,不过 Reflect & Proxy 远远比它强大。大多数开发者都了解这两个 Es6 中的新增内置模块,可是你...

zz_jesse的博客 148

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

ES6-ECMAScript6

d.dead zone 死区。

likeablegirl88的博客 45

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

深入探索 Reflect:掌握对象操作的强大工具

本文详细介绍了 JavaScript 中的 Reflect 对象,解释了其方法如 apply、construct、defineProperty、deleteProperty 等的作用和使用场景,强调了它简化和统一对象操作的优势,并展示了与 Proxy 结合的应用。

weixin_52648900的博客 1817

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

ES6 面试题 | 15.精选 ES6 面试题

代理对象(Proxy)和反射对象(Reflect)是ES6中引入的两个新概念,它们的作用是提供对对象属性和方法的操作。代理对象(Proxy):代理对象可以拦截对目标对象的读取和写入操作,可以对目标对象的属性进行修改、添加或删除等操作。代理对象可以用于实现数据验证、访问控制、日志记录等功能。// 输出:Accessing: name// 输出:Accessing: age// 输出:Updating: name Jane// 输出:Jane。

青轩桃李能几何,流光欺人忽蹉跎 928

【JS】1471- 为什么Proxy一定要配合Reflect使用?

引言EcmaScript 2015 中引入了Proxy 代理[1]与Reflect 反射[2]两个新的内置模块。我们可以利用 Proxy 和 Reflect 来实现对于对象的代理劫持操作,类似于 Es 5 中Object.defineProperty\(\)[3]的效果,不过 Reflect & Proxy 远远比它强大。大多数开发者都了解这两个 Es6 中的新增内置模块,可是你...

pingan8787 412

为什么Proxy一定要配合Reflect使用?万字详解

摘要:ES6引入的Proxy和Reflect是JavaScript元编程的核心API,它们协同工作提供了强大的拦截和自定义对象操作能力。Proxy作为拦截器,通过13种陷阱方法覆盖对象基本操作;Reflect则提供与Proxy对应的操作方法,确保正确的this绑定和操作一致性。两者配合的必要性在于:1)维护正确的this指向(通过receiver参数);2)保持操作与语言内部行为一致;3)提供标准化的返回值。典型应用包括数据验证、依赖追踪和AOP编程。最佳实践表明,在Proxy陷阱中应始终使用Reflect

油墨香^-^的博客 257

ES6 Proxy 和 Reflect 用法

前言:ES6 Proxy和Reflect是一个蛮有用的组合,这两个属性相辅相成。这篇文章是通过用这两个属性来写一个 简单的常用实例。也通过这个实例来说明Proxy和Reflect几个常用的方法。Proxy是什么?Proxy用于修改某些操作的默认行为,等同于在语言层面作出修改,需要一种“元编程”,即对编程语言进行编程。可以理解为对目标对象设置“拦截”层,外界访问该对象必须先通过拦截层。因此提供了一种机

rth362147773的博客 846

ES2015(ES6)+

JES2015-ES6目录名词释义ECMAScriptES2015ES6let 和 const箭头函数函数的参数默认值用法示例模板字符串扩展(展开) 运算符解构赋值对象解构赋值数组的解构赋值应用-解构赋值结合函数声明对象成员的简写概述Symbol作为对象属性Symbol.for内置SymbolSymbol的属性Set和WeakSetSet实例WeakSetMap和WeakMapMap实例1:扩展对象实例2:完善私有属性的实现WeakMap实例:完善私有属性的实现ProxyReflect 反射Iterator

weixin_46873254的博客 1904

JavaScript Proxy与Reflect:元编程核心原理与工程实践

Proxy和Reflect是ECMAScript定义的底层元编程机制,用于在不修改原对象的前提下拦截并自定义对象行为。其核心原理是通过trap陷阱捕获属性访问、函数调用、构造操作等运行时行为,并借助Reflect提供标准化委托接口,确保拦截逻辑可逆、可组合、可测试。技术价值在于实现响应式系统(如Vue 3)、权限控制、数据脱敏、日志监控等横切关注点;典型应用场景包括状态代理、API封装、调试工具增强及高性能缓存策略。本文深入解析13个trap的设计意图、Reflect与Object方法的本质差异,以及生产环

chubaisheng8627的博客 357
上一篇: ES2015 对象字面量增强与扩展方法
下一篇: HTML:你和我的第一次,就这样简单吗
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值