ECMAScript 2016 (ES7) 新特性之 Proxy 和 Reflect

阅读时长 9 分钟读完

简介

ECMAScript 2016 (ES7) 新增了 Proxy 和 Reflect 两个对象操作 API,Proxy 可以代理对象操作,而 Reflect 提供了一系列操作对象的方法,两者的配合使用使得 JavaScript 对象的操作更加灵活和可控。

本文将详细介绍 Proxy 和 Reflect 的使用方法,包括它们的基本语法、应用场景以及常用的技巧。

Proxy

概述

Proxy 可以拦截对象的各种操作,如读取、赋值、方法调用等,使用 Proxy 可以代理对象的操作,从而加入自定义逻辑,并最终将其传达到原始对象。

-- -------------------- ---- -------
----- --- - --- --------- -
  ---- -------- -------- ---- --------- -
    --------------------- ------ -----
    ------ ------------------- ---- ---------- --------------
  --
  ---- -------- -------- ---- ------ --------- -
    --------------------- ------ --- -----------
    ------ ------------------- ---- ------ ---------- --------------
  -
---

----------- - ------- -------- ---------------- ------- --- ------ ------
------------------------- ---------------- ------- --
展开代码

如上代码所示,我们通过 Proxy 对象定义了一个代理对象,通过 get 和 set 方法,拦截了对象属性的读取和赋值操作,并实现了自定义的逻辑。

参数

Proxy 构造函数接收两个参数,分别为待代理的目标对象和一个结构体,结构体用于定义拦截器函数。

代理对象的拦截器函数分为以下 13 种操作:

  • get(target, property, receiver):拦截对象属性的读取操作。
  • set(target, property, value, receiver):拦截对象属性的赋值操作。
  • has(target, property):拦截 in 操作符并返回一个布尔值。如果原始对象拥有指定的属性,则为 true;否则为 false。
  • ownKeys(target):返回一个数组,包含原始对象的所有可枚举属性。
  • construct(target, args, newTarget):拦截 new 操作符,并返回一个构造函数的实例。
  • defineProperty(target, property, descriptor):拦截 Object.defineProperty 操作并返回一个布尔值缩写该操作是否成功。
  • deleteProperty(target, property):拦截 delete 操作符并返回一个布尔值缩写该操作是否成功。
  • getOwnPropertyDescriptor(target, property):拦截 Object.getOwnPropertyDescriptor 方法。用于拦截获取特定对象属性的描述符操作。
  • getPrototypeOf(target):拦截 Object.getPrototypeOf 方法。用于拦截获取对象原型操作。
  • isExtensible(target):拦截 Object.isExtensible 方法。如果原始对象不可扩展,则返回一个布尔值表示其是否可扩展。
  • preventExtensions(target):拦截 Object.preventExtensions 操作。目的是使得不可扩展的对象不再可扩展。
  • setPrototypeOf(target, prototype):拦截 Object.setPrototypeOf 操作。用于设置对象的原型。
  • apply(target, object, args):拦截函数的调用操作。

应用场景

数据校验

在实际应用中,经常需要对前端操作的数据进行校验。有些校验可以在数据存储时进行,但使用 Proxy 能够更为灵活地进行校验。

-- -------------------- ---- -------
----- --- - --- --------- -
  ---- -------- -------- ---- ------ --------- -
    -- ------ -- -- -
      ----- ------------------
    - ---- -
      ------ ------------------- ---- ------ ----------
    -
  -
---

---------- - ---- ------------------
------------------------ -----------
---------- - ----- ------
展开代码

上述示例中,我们实现了对数据属性的校验,如果设置的值小于等于零,则会抛出异常。

跨域代理

浏览器实现了 XMLHttpRequest 对象,允许向其他域提交请求。在这种情况下,可以使用 Proxy 对象来代理请求目标的地址。

-- -------------------- ---- -------
----- --------- - --------------------------------------
----- --- - ----------------------------------------
----- -------- - -----------------------------------------
----------
  --------- -- -----------
  ---------- -- -------------------
---------------
  --------- -- -----------
  ---------- -- -------------------
展开代码

上述代码中,我们将请求的地址代理到 Proxy 服务器,以此防止跨域访问限制。

Reflect

概述

Reflect 提供了一组操作对象的 API,能够对对象进行一系列操作,提供对方法的默认行为重现。

如上代码所示,我们调用 in 操作符来判断对象是否拥有指定属性,这个操作符可以被 Reflect.has 方法所替代。

API

Reflect 对象提供了以下 13 个静态方法,用于对象的操作,其中大多数方法与 Proxy 对象的拦截器函数相对应。

  • Reflect.apply(target, thisArg, args):在指定的 this 对象上调用给定的函数,并将给定的参数列表传递给函数。
  • Reflect.construct(target, args):使用给定的参数列表创建指定的对象。
  • Reflect.defineProperty(target, propertyKey, attributes):定义对象的一个属性。
  • Reflect.deleteProperty(target, propertyKey):从对象中删除指定的属性。
  • Reflect.get(target, propertyKey, receiver):返回对象上的指定属性。
  • Reflect.getOwnPropertyDescriptor(target, propertyKey):返回指定对象上的属性的属性描述符。
  • Reflect.getPrototypeOf(target):返回对象的原型。
  • Reflect.has(target, propertyKey):返回一个布尔值,表示对象是否具有指定的属性。
  • Reflect.isExtensible(target):如果对象是可扩展的,则返回 true。
  • Reflect.ownKeys(target):返回一个包含所有自身属性(不包括继承属性)名称的数组。
  • Reflect.preventExtensions(target):将对象设为不可扩展(即不能再添加新的属性)。
  • Reflect.set(target, propertyKey, value, receiver):设定对象的指定属性为指定的值。
  • Reflect.setPrototypeOf(target, prototype):将目标对象的原型设置为新原型或另一个对象。

应用场景

固化对象属性

在 JavaScript 中,对象的属性通常是可修改的,因此在一些场景中,需要固化对象的属性,使其不能被修改。

上述示例中,我们使用 Reflect 解决了对象属性可修改的问题,将对象属性定义为只读的。

利用默认行为处理代理

在 Proxy 中,我们常常需要将某些操作传递给原始对象,以此保留原始对象的默认行为。

-- -------------------- ---- -------
----- --- - - ----- ------- ---- -- --
----- ----- - --- ---------- -
  ---- ---------------- ---- --------- -
    --------------------- ------ -----
    ------ ------------------- ---- ----------
  --
  ---- ---------------- ---- ------ --------- -
    ------------------- ---- ------ ----------
    --------------------- ------ --- -----------
    ------ -----
  --
  --------------- ---------------- ---- -
    ------ ------------------------------ -----
  -
---

----------- -------------
--------- - --- -------------
------ ----------- -------------
展开代码

上述示例中,我们修改了 Proxy 中的 get、set 和 deleteProperty 方法,但在方法内部,仍然使用 Reflect 将操作传递给了原始对象,以此保留了对象的默认行为。

结语

本文详细介绍了 Proxy 和 Reflect 的各种应用场景和使用技巧,希望读者能够掌握这两个 API,在实际编程中运用自如。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67c7dce4cc0f7239cdfdb1d5

纠错
反馈

纠错反馈

程序员教程

精选优质教程,助你快速提升技术实力

程序员面试题库

海量优质面试题,助你轻松应对技术面试