前置条件

在开发过程中遇到的一个具有挑战性的需求,涉及到一个独特且复杂的数据结构,这直接关系到如何有效地更新建筑信息

这个项目需求源自于对建筑数据精确管理的必要性,其中建筑数据按照其属性被划分为三种主要类型:多栋建筑、独栋建筑以及局部建筑

多栋建筑是指那些包含若干子建筑单元的复合体,它们共享一套总体的数据——大约10余条重要的信息,并且拥有一个庞大的数组,这个数组详细记录了其中每一个子建筑或局部建筑的详细信息,每个子单元的数据大约包含40至50条具体信息

独栋建筑在数据结构上与多栋建筑中的单个建筑单元类似,同样维护着大约40至50条的详细信息,但它独立存在,不属于任何多栋建筑的一部分

局部建筑则相对较小,包含的数据项约30条,关注点更集中在具体的、局部的部分上


鉴于建筑数据的复杂性和数量众多,我们设计了专门的数据接口来处理查询和更新操作

局部建筑由单一的接口管理,而栋建筑的数据则通过四个不同的接口进行操作,多栋建筑最为复杂,需要六个接口来维护其数据的准确性和时效性

面对这种需求,关键在于如何在用户对某个建筑的数据进行编辑或修改时,能够准确地捕捉到这些变动,并通过正确的接口将更新推送至服务器

为了实现这一目标,我借鉴了Vue3的核心设计理念,采用了Proxy技术

这使得我们能够以一种智能且效率高的方式监听数据的变化,一旦侦测到用户对数据的编辑或更新,就能迅速准确地分析出需要调用的接口类型,进而完成数据的同步更新


为什么选Proxy

在项目开发过程中,我们深入讨论并评估了几种不同的数据更新策略,目的是为了找到最适合我们复杂应用需求的方法

以下是我们考虑的三个方案:

  1. 方案一:事件监听
    描述:通过在模板中对相关节点设置@change事件监听来处理数据更新
    评估:此方法虽然直接且易于实现,但当面对复杂交互时,显著增加了HTML编码的工作量及重复性的函数定义,导致代码维护成本上升
  2. 方案二:Proxy
    描述:利用JavaScript的Proxy特性来拦截对象的操作,从而实现数据的响应式更新
    评估:Proxy能够提供一套强大的数据监听与拦截机制,但由于其在Vue3项目中的应用相对较新,对于部分开发者而言,学习与应用的门槛相对较高
  3. 方案三:全量更新
    描述:每当数据发生变化时,请求服务器并全面更新页面数据
    评估:尽管这种方法实现起来较为简单,但它对服务器资源的消耗过大,在面向大规模用户(如一个省份级别的用户群体)的项目中,这种做法显然是不经济、不实际的
proxy

Proxy 是 ES6 引入的一种机制,它允许我们创建一个对象,该对象可以拦截并自定义基本操作(例如属性查找、赋值、枚举、函数调用等)

  1. Proxy 对象的基本概念

    Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

    Proxy 由两个部分组成:

    • 目标对象:代理将虚拟化该对象的某些操作
    • 处理器(handler):一个对象,其属性是当执行一个操作时定义代理行为的函数
  2. 使用场景

    • 数据验证:可以在对象属性赋值时进行验证
    • 属性代理:可以代理对象的属性访问和修改
    • 函数代理:可以代理函数的调用
    • 观察者模式:可以用来实现观察者模式,监听对象的变化
  3. 注意事项

    • 性能开销:过度使用 Proxy 可能会带来性能开销
    • 兼容性Proxy 在某些旧版本的浏览器中可能不受支持,尤其是 IE 浏览器。因此,在使用 Proxy 时,确保你的代码运行环境支持它
    • 不可代理的对象:某些内置对象和函数不允许被代理,例如 Function.prototype
    • 陷阱限制:某些陷阱有具体的行为限制。例如,get 陷阱不能返回未定义的属性,而 set 陷阱必须返回 truefalse
  4. 代理的局限性

    虽然 Proxy 非常强大,但它也有一些局限性:

    • 不可代理的内置对象:某些 JavaScript 内置对象无法被代理,如 ArrayBuffer
    • 性能问题:代理每次操作都会触发陷阱,这可能会导致性能问题,特别是在需要高性能的场景中
    • 调试困难:由于代理的动态特性,调试代理对象可能会更加复杂
    • 递归代理:如果需要深度代理对象(例如嵌套对象),需要递归地创建代理,这可能会增加代码复杂性
  5. 代理的实际用例

    • 数据绑定:在前端框架中,Proxy 常用于实现数据绑定。例如 Vue 3 中的响应式系统就是基于 Proxy 实现的
    • 访问控制:可以用 Proxy 来控制对对象属性的访问。例如,可以限制某些属性的可读性或可写性
    • 日志记录:可以用 Proxy 来记录对对象的所有操作,便于调试和监控


代码实现

定义Proxy的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!--
* @Description: Proxy代理对象
* @Author: 5t5
* @Time: 2023/1/13 23:18
-->

export default class ProxyDeep {
constructor(){

}
/**
* 初始化对象或数组的深度代理
* @param {Object|Array} obj - 需要代理的目标对象或数组
* @param {Object} handle - 代理处理器对象
* @returns {Proxy|null} - 返回代理对象或null(如果目标非法)
*/
initProxy(obj, handle) {
// 检查传入的目标是否为对象或数组
if (!obj || typeof obj !== 'object') {
console.error('Illegal agent target: Target must be an object or array.')
return null
}

// 检查代理处理器是否为对象
if (!handle || typeof handle !== 'object') {
console.error('Illegal handler: Handler must be an object.')
return null
}

// 辅助函数,用于检查值是否为对象(包括数组)
const isObject = (val) => val !== null && typeof val === 'object'

/**
* 递归遍历目标对象或数组,将其所有嵌套对象和数组都代理化
* @param {Object|Array} target - 当前处理的对象或数组
* @returns {Object|Array|null} - 处理后的对象或数组
*/
const traverse = (target) => {
// 如果目标是数组
if (Array.isArray(target)) {
// 遍历数组的每一项
for (let i = 0; i < target.length; i++) {
// 如果当前项是对象或数组,则递归调用traverse进行处理
if (isObject(target[i])) {
target[i] = traverse(target[i])
}
}
} else {
// 如果目标是对象
// 遍历对象的每一个属性
for (const key in target) {
// 确保只处理对象自身的属性
if (target.hasOwnProperty(key) && isObject(target[key])) {
target[key] = traverse(target[key])
}
}
}

// 返回处理后的目标
return target
}

// 对传入的对象或数组进行遍历处理,并返回代理后的对象
return new Proxy(traverse(obj), handle)
}
}

注释解释

  1. 类及构造函数
    • ProxyDeep 类的构造函数目前没有任何初始化操作,留空即可
  2. initProxy 方法
    • 参数
      • obj:需要代理的目标对象或数组
      • handle:代理处理器对象,定义了代理的行为
    • 返回值
      • 如果目标非法(null 或者非对象类型),返回 null
      • 否则,返回代理后的对象或数组
    • 逻辑
      • 首先检查目标是否为对象或数组,如果不是则打印错误信息并返回 null
      • 定义辅助函数 isObject 用于检查值是否为对象(包括数组)
      • 定义递归函数 traverse,用于遍历目标对象或数组的所有嵌套对象和数组,并将其代理化
      • 最后,调用 traverse 函数处理传入的对象或数组,并返回代理后的结果
  3. traverse 函数
    • 参数
      • target:当前处理的对象或数组
    • 返回值
      • 处理后的对象或数组
    • 逻辑
      • 如果目标是数组,遍历数组的每一项,如果当前项是对象或数组,则递归调用 traverse 进行处理
      • 如果目标是对象,遍历对象的每一个属性,如果当前属性值是对象或数组,则递归调用 traverse 进行处理
      • 返回处理后的目标
为什么数组不做代理

当你代理一个包含数组的对象时,通常来说,你拦截的是对object属性的操作,而不是直接对数组内部元素的操作

如果你的操作目标是一个object的属性,那么只要这个属性的访问或者修改被Proxy拦截,你就能对这个操作进行控制

当代理目标对象中的属性是数组时,实际上你代理的是对这个数组属性的访问和修改,而不是数组内部元素本身

如果直接操作数组(如直接修改数组元素的值、添加新元素等操作),这些操作是不会被属性访问的拦截器(如getset)捕获的,因为它们不是属性访问操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const target = {
array: [1, 2, 3]
};

// 正在创建代理
const proxy = new Proxy(target, {
get(target, prop, receiver) {
if (prop === 'array') {
return new Proxy(target[prop], {
// ... 无论你在这里定义什么拦截逻辑
});
}

return Reflect.get(target, prop, receiver);
}
});

如果你将目标对象中的数组也设置为一个代理,并且在这个新的代理中又返回了对原始数组的代理,那么可能会出现递归代理的情况,这可能导致栈溢出错误

这是因为你可能错误地创建了一个无限循环的代理,每次访问数组都会再次调用代理,如此无限循环下去

每次通过代理对象访问array属性时,代码都将创建数组的一个新代理

如果代理的get陷阱返回了另一个代理,那么下次再次访问array属性,就会再次创建新的代理,从而导致递归调用,最终抛出栈溢出错误


定义handle处理对象

此为示例,具体实现可以根据项目需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const handle = {
// 拦截属性访问
get(target, property, receiver) {
console.log(`Getting property '${property}'`)
// 该函数在获取代理对象对应的值的时候会触发
return Reflect.get(target, property, receiver)
},

// 拦截属性设置
set(target, property, value, receiver) {
console.log(`Setting property '${property}' to '${value}'`)
// 该函数在设置代理对象对应的值的时候会触发
return Reflect.set(target, property, value, receiver)
}
}
handle

关于 Proxyhandler 对象是 Proxy 的核心部分之一

它定义了拦截操作的行为

通过在 handler 对象中定义特定的陷阱(trap),你可以拦截和自定义对象的各种操作行为

  1. 基本结构

    一个 handler 对象是一个包含多个陷阱方法的普通 JavaScript 对象

    每个陷阱方法对应一个对象操作,例如属性访问、属性设置、函数调用等

  2. 常见陷阱方法

    示例对象使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 示例对象
    const targetObject = {
    a: 1,
    b: 2,
    c: 3
    };

    // 创建代理对象
    const proxy = new Proxy(targetObject, handle);

    以下方法都是基于这个例子

    • get(target, property, receiver)

      拦截属性访问操作,例如 proxy.property

      • 参数
        • target:被代理的目标对象
        • property:被访问的属性名
        • receiver:代理对象或继承代理对象的对象
      • 作用:拦截属性访问操作
      • 返回值:返回属性的值
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      get(target, property, receiver) {
      console.log(`Getting property ${property}`);
      return Reflect.get(target, property, receiver);
      }

      }

      // 代理对象的操作示例
      console.log(proxy.a); // Getting property a
    • set(target, property, value, receiver)

      拦截属性设置操作,例如 proxy.property = value

      • 参数
        • target:被代理的目标对象
        • property:被设置的属性名
        • value:要设置的属性值
        • receiver:代理对象或继承代理对象的对象
      • 作用:拦截属性设置操作
      • 返回值:必须返回一个布尔值,表示是否成功设置属性
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      set(target, property, value, receiver) {
      console.log(`Setting property ${property} to ${value}`);
      return Reflect.set(target, property, value, receiver);
      }

      }

      // 代理对象的操作示例
      proxy.b = 10; // Setting property b to 10
    • has(target, property)

      拦截 in 操作符,例如 property in proxy

      • 参数
        • target:被代理的目标对象
        • property:要检查的属性名
      • 作用:拦截 in 操作符
      • 返回值:返回一个布尔值,表示属性是否存在
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      has(target, property) {
      console.log(`Checking if property ${property} exists`);
      return Reflect.has(target, property);
      }

      }

      // 代理对象的操作示例
      console.log('b' in proxy); // Checking if property b exists
    • deleteProperty(target, property)

      拦截 delete 操作符,例如 delete proxy.property

      • 参数
        • target:被代理的目标对象
        • property:要删除的属性名
      • 作用:拦截 delete 操作符
      • 返回值:返回一个布尔值,表示属性是否成功删除
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      deleteProperty(target, property) {
      console.log(`Deleting property ${property}`);
      return Reflect.deleteProperty(target, property);
      }

      }

      // 代理对象的操作示例
      delete proxy.c; // Deleting property c
    • ownKeys(target)

      拦截对象自身属性的枚举操作,例如 Object.keys(proxy)

      • 参数
        • target:被代理的目标对象
      • 作用:拦截对象自身属性的枚举操作,例如 Object.keys(proxy)for...in 循环
      • 返回值:返回一个包含目标对象自身属性的数组
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      ownKeys(target) {
      console.log(`Getting own keys of the target`);
      return Reflect.ownKeys(target);
      }

      }

      // 代理对象的操作示例
      console.log(Object.keys(proxy)); // Getting own keys of the target
    • getOwnPropertyDescriptor(target, property)

      拦截 Object.getOwnPropertyDescriptor(proxy, property)

      • 参数
        • target:被代理的目标对象
        • property:要获取描述符的属性名
      • 作用:拦截 Object.getOwnPropertyDescriptor(proxy, property)
      • 返回值:返回属性描述符对象或 undefined
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      getOwnPropertyDescriptor(target, property) {
      console.log(`Getting descriptor for property ${property}`);
      return Reflect.getOwnPropertyDescriptor(target, property);
      }

      }

      // 代理对象的操作示例
      console.log(Object.getOwnPropertyDescriptor(proxy, 'a')); // Getting descriptor for property a
    • defineProperty(target, property, descriptor)

      拦截 Object.defineProperty(proxy, property, descriptor)

      • 参数
        • target:被代理的目标对象
        • property:要定义或修改的属性名
        • descriptor:属性描述符对象
      • 作用:拦截 Object.defineProperty(proxy, property, descriptor)
      • 返回值:返回一个布尔值,表示属性是否成功定义或修改
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      defineProperty(target, property, descriptor) {
      console.log(`Defining property ${property} with descriptor`);
      return Reflect.defineProperty(target, property, descriptor);
      }

      }

      // 代理对象的操作示例
      Object.defineProperty(proxy, 'd', { value: 4, writable: true }); // Defining property d with descriptor
    • preventExtensions(target)

      拦截 Object.preventExtensions(proxy)

      • 参数
        • target:被代理的目标对象
      • 作用:拦截 Object.preventExtensions(proxy)
      • 返回值:返回一个布尔值,表示对象是否成功被标记为不可扩展
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      preventExtensions(target) {
      console.log(`Preventing extensions on the target`);
      return Reflect.preventExtensions(target);
      }

      }

      // 代理对象的操作示例
      Object.preventExtensions(proxy); // Preventing extensions on the target
    • isExtensible(target)

      拦截 Object.isExtensible(proxy)

      • 参数
        • target:被代理的目标对象
      • 作用:拦截 Object.isExtensible(proxy)
      • 返回值:返回一个布尔值,表示对象是否是可扩展的
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      isExtensible(target) {
      console.log(`Checking if the target is extensible`);
      return Reflect.isExtensible(target);
      }

      }

      // 代理对象的操作示例
      console.log(Object.isExtensible(proxy)); // Checking if the target is extensible
    • getPrototypeOf(target)

      拦截 Object.getPrototypeOf(proxy)

      • 参数
        • target:被代理的目标对象
      • 作用:拦截 Object.getPrototypeOf(proxy)
      • 返回值:返回目标对象的原型对象
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      getPrototypeOf(target) {
      console.log(`Getting prototype of the target`);
      return Reflect.getPrototypeOf(target);
      }

      }

      // 代理对象的操作示例
      console.log(Object.getPrototypeOf(proxy)); // Getting prototype of the target
    • setPrototypeOf(target, prototype)

      拦截 Object.setPrototypeOf(proxy, prototype)

      • 参数
        • target:被代理的目标对象
        • prototype:新的原型对象
      • 作用:拦截 Object.setPrototypeOf(proxy, prototype)
      • 返回值:返回一个布尔值,表示原型是否成功设置
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const handle = {

      setPrototypeOf(target, prototype) {
      console.log(`Setting prototype of the target`);
      return Reflect.setPrototypeOf(target, prototype);
      }

      }

      // 代理对象的操作示例
      Object.setPrototypeOf(proxy, null); // Setting prototype of the target
    • apply(target, thisArg, argumentsList)

      拦截函数调用,例如 proxy(...args)

      • 参数
        • target:被代理的目标函数
        • thisArg:调用函数时的 this
        • argumentsList:调用函数时的参数列表
      • 作用:拦截函数调用操作,例如 proxy(...args)
      • 返回值:返回函数调用的结果
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      const handle = {

      apply(target, thisArg, argumentsList) {
      console.log(`Applying function with arguments ${argumentsList}`);
      return Reflect.apply(target, thisArg, argumentsList);
      }

      }

      // 函数代理示例
      const targetFunction = function(a, b) {
      return a + b;
      };

      const proxyFunction = new Proxy(targetFunction, handler);
      console.log(proxyFunction(1, 2)); // Applying function with arguments 1,2
    • construct(target, argumentsList, newTarget)

      拦截构造函数调用,例如 new proxy(...args)

      • 参数
        • target:被代理的目标构造函数
        • argumentsList:调用构造函数时的参数列表
        • newTarget:创建实例时的构造函数
      • 作用:拦截构造函数调用操作,例如 new proxy(...args)
      • 返回值:返回一个新的对象
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      const handle = {

      construct(target, argumentsList, newTarget) {
      console.log(`Constructing new instance with arguments ${argumentsList}`);
      return Reflect.construct(target, argumentsList, newTarget);
      }

      }

      // 构造函数代理示例
      class TargetClass {
      constructor(name) {
      this.name = name;
      }
      }

      const proxyClass = new Proxy(TargetClass, handler);
      const instance = new proxyClass('Proxy'); // Constructing new instance with arguments Proxy
      console.log(instance.name);
Reflect

Reflect 对象是ES6(ECMAScript 2015)引入的一个内置对象,它提供了一些方法用于操作对象的属性和原型

Reflect 对象的设计目的是为了与 Proxy 对象一起使用,提供更一致和可预测的行为

Reflect 对象的方法与 Object 对象的方法类似,但有一些关键的区别

  1. 与 Proxy 的关系

    Reflect 对象的设计初衷是为了与 Proxy 对象配合使用

    Proxy 对象可以拦截并自定义基本操作(例如属性查找、赋值、枚举、函数调用等),而 Reflect 提供了默认的行为实现

    这样,使用 Reflect 可以更容易地在 Proxy 中调用默认行为

  2. 一致性和简洁性

    Reflect 方法的命名和参数顺序与 Proxy 的捕获器(trap)方法保持一致

    这种一致性使得代码更易读,也更容易理解和维护

  3. 返回值

    Reflect 方法通常返回布尔值来指示操作是否成功,而不是像某些 Object 方法那样抛出异常

    例如,Reflect.defineProperty 在属性定义失败时返回 false,而不是抛出异常

  4. 避免重复代码

    在编写 Proxy 处理器时,使用 Reflect 可以避免重复代码

    例如,在 set 捕获器中,可以使用 Reflect.set 来执行默认的属性赋值操作

方法详解

  1. Reflect.apply(target, thisArgument, argumentsList)

    • 描述: 调用一个目标函数,并传入指定的 this 值和参数

    • 参数

      • target: 目标函数
      • thisArgument: 函数调用时的 this
      • argumentsList: 一个数组或类数组对象,包含要传递给函数的参数
    • 返回值: 函数调用的结果

    • 示例

      1
      2
      3
      4
      5
      function sum(a, b) {
      return a + b;
      }
      const result = Reflect.apply(sum, null, [1, 2]);
      console.log(result); // 3
  2. Reflect.construct(target, argumentsList[, newTarget])

    • 描述: 等同于使用 new 操作符调用一个构造函数

    • 参数

      • target: 目标构造函数
      • argumentsList: 一个数组或类数组对象,包含要传递给构造函数的参数
      • newTarget (可选): 新创建对象的原型。如果未提供,则默认为 target
    • 返回值: 新创建的对象

    • 示例

      1
      2
      3
      4
      5
      function Person(name) {
      this.name = name;
      }
      const person = Reflect.construct(Person, ['Alice']);
      console.log(person.name); // Alice
  3. Reflect.defineProperty(target, propertyKey, attributes)

    • 描述: 类似于 Object.defineProperty,定义对象的属性

    • 参数

      • target: 目标对象
      • propertyKey: 属性键
      • attributes: 属性描述符
    • 返回值: 布尔值,表示属性是否成功定义

    • 示例

      1
      2
      3
      4
      const obj = {};
      const success = Reflect.defineProperty(obj, 'name', { value: 'Alice' });
      console.log(success); // true
      console.log(obj.name); // Alice
  4. Reflect.deleteProperty(target, propertyKey)

    • 描述: 删除对象的属性

    • 参数

      • target: 目标对象
      • propertyKey: 属性键
    • 返回值: 布尔值,表示属性是否成功删除

    • 示例

      1
      2
      3
      4
      const obj = { name: 'Alice' };
      const success = Reflect.deleteProperty(obj, 'name');
      console.log(success); // true
      console.log(obj.name); // undefined
  5. Reflect.get(target, propertyKey[, receiver])

    • 描述: 获取对象的属性值

    • 参数

      • target: 目标对象
      • propertyKey: 属性键
      • receiver (可选): 如果是一个代理对象,则作为 this 值传递给 getter 函数
    • 返回值: 属性值

    • 示例

      1
      2
      3
      const obj = { name: 'Alice' };
      const value = Reflect.get(obj, 'name');
      console.log(value); // Alice
  6. Reflect.getOwnPropertyDescriptor(target, propertyKey)

    • 描述: 获取对象自身属性的属性描述符。

    • 参数

      • target: 目标对象
      • propertyKey: 属性键
    • 返回值: 属性描述符对象或 undefined

    • 示例

      1
      2
      3
      const obj = { name: 'Alice' };
      const descriptor = Reflect.getOwnPropertyDescriptor(obj, 'name');
      console.log(descriptor); // { value: 'Alice', writable: true, enumerable: true, configurable: true }
  7. Reflect.getPrototypeOf(target)

    • 描述: 获取对象的原型

    • 参数

      • target: 目标对象
    • 返回值: 目标对象的原型

    • 示例

      1
      2
      3
      const obj = {};
      const proto = Reflect.getPrototypeOf(obj);
      console.log(proto); // Object.prototype
  8. Reflect.has(target, propertyKey)

    • 描述: 检查对象是否具有某个属性(包括原型链上的属性)

    • 参数

      • target: 目标对象
      • propertyKey: 属性键
    • 返回值: 布尔值,表示属性是否存在

    • 示例

      1
      2
      3
      const obj = { name: 'Alice' };
      const hasName = Reflect.has(obj, 'name');
      console.log(hasName); // true
  9. Reflect.isExtensible(target)

    • 描述: 检查对象是否可扩展(即是否可以添加新属性)

    • 参数

      • target: 目标对象
    • 返回值: 布尔值,表示对象是否可扩展

    • 示例

      1
      2
      3
      const obj = {};
      const extensible = Reflect.isExtensible(obj);
      console.log(extensible); // true
  10. Reflect.ownKeys(target)

    • 描述: 获取对象的所有属性键,包括不可枚举属性和符号属性

    • 参数

      • target: 目标对象
    • 返回值: 包含对象所有属性键的数组

    • 示例

      1
      2
      3
      const obj = { name: 'Alice' };
      const keys = Reflect.ownKeys(obj);
      console.log(keys); // ['name']
  11. Reflect.preventExtensions(target)

    • 描述: 防止对象扩展(即不允许添加新属性)

    • 参数

      • target: 目标对象
    • 返回值: 布尔值,表示操作是否成功

    • 示例

      1
      2
      3
      4
      const obj = {};
      const success = Reflect.preventExtensions(obj);
      console.log(success); // true
      console.log(Reflect.isExtensible(obj)); // false
  12. Reflect.set(target, propertyKey, value[, receiver])

    • 描述: 设置对象的属性值

    • 参数

      • target: 目标对象
      • propertyKey: 属性键
      • value: 要设置的值
      • receiver (可选): 如果是一个代理对象,则作为 this 值传递给 setter 函数
    • 返回值: 布尔值,表示属性是否成功设置

    • 示例

      1
      2
      3
      4
      const obj = {};
      const success = Reflect.set(obj, 'name', 'Alice');
      console.log(success); // true
      console.log(obj.name); // Alice
  13. Reflect.setPrototypeOf(target, proto)

    • 描述: 设置对象的原型

    • 参数

      • target: 目标对象
      • proto: 新的原型对象
    • 返回值: 布尔值,表示原型是否成功设置

    • 示例

      1
      2
      3
      4
      5
      const obj = {};
      const proto = { greeting: 'Hello' };
      const success = Reflect.setPrototypeOf(obj, proto);
      console.log(success); // true
      console.log(obj.greeting); // Hello


使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<!-- 建筑的结构代码 -->
</template>

<script setup>
import ProxyDeep from '@/utils/proxyDeep'

const targetData = {}
const proxyDeep = new ProxyDeep()
const handler = {... code ...}

const startProxy = (info) => {
... code ...
targetData = proxyDeep.initProxy(info, handler)
}
</script>