当前位置: 首页 > news >正文

ES6 Proxy 用法总结以及 Object.defineProperty用法区别

Proxy 是 ES6 引入的一种强大的拦截机制,用于定义对象的基本操作(如读取、赋值、删除等)的自定义行为。相较于 Object.definePropertyProxy 提供了更灵活、全面的拦截能力。


1. Proxy 语法

const proxy = new Proxy(target, handler);
  • target:被代理的对象
  • handler:定义拦截行为的对象

2. Proxy 基本用法

(1) 拦截对象的属性访问

const person = {
  name: "Alice",
  age: 25,
};

const proxyPerson = new Proxy(person, {
  get(target, prop) {
    console.log(`访问属性: ${prop}`);
    return prop in target ? target[prop] : "属性不存在";
  },
});

console.log(proxyPerson.name); // 访问属性: name  -> "Alice"
console.log(proxyPerson.gender); // 访问属性: gender  -> "属性不存在"

(2) 拦截对象的属性修改

const proxyPerson = new Proxy(person, {
  set(target, prop, value) {
    if (prop === "age" && typeof value !== "number") {
      throw new Error("年龄必须是数字");
    }
    target[prop] = value;
    console.log(`设置 ${prop}${value}`);
    return true;
  },
});

proxyPerson.age = 30; // 设置 age 为 30
proxyPerson.age = "abc"; // 抛出错误: 年龄必须是数字

(3) 拦截对象的属性删除

const proxyPerson = new Proxy(person, {
  deleteProperty(target, prop) {
    console.log(`删除属性: ${prop}`);
    return delete target[prop];
  },
});

delete proxyPerson.age; // 删除属性: age

(4) 拦截 in 操作符 (has 方法)

const proxyPerson = new Proxy(person, {
  has(target, prop) {
    console.log(`检查属性是否存在: ${prop}`);
    return prop in target;
  },
});

console.log("name" in proxyPerson); // 检查属性是否存在: name -> true
console.log("gender" in proxyPerson); // 检查属性是否存在: gender -> false
const range = { start: 10, end: 50 };

const proxy = new Proxy(range, {
  has(target, prop) {
    return prop >= target.start && prop <= target.end;
  }
});

console.log(15 in proxy); // true
console.log(60 in proxy); // false

(5) 拦截函数调用 (apply 方法)

const multiply = new Proxy((a, b) => a * b, {
  apply(target, thisArg, args) {
    console.log(`调用函数 multiply,参数: ${args}`);
    return target(...args);
  }
});

console.log(multiply(3, 4)); // 调用函数 multiply,参数: 3,4 -> 12

(6) 拦截构造函数 (construct 方法)

const Person = new Proxy(class {
  constructor(name) {
    this.name = name;
  }
}, {
  construct(target, args) {
    console.log(`创建实例,参数: ${args}`);
    return new target(...args);
  }
});

const user = new Person("Alice"); // 创建实例,参数: Alice

特点:

  • 可以 监听整个对象,而不是单个属性。
  • 能拦截 所有操作(如 getsethasdeletePropertyapply 等)。
  • 可以用于 动态代理,使得代码更具扩展性。

3. Proxy 实际使用场景

(1) 数据验证和格式化

const user = new Proxy({}, {
  set(target, prop, value) {
    if (prop === "age" && typeof value !== "number") {
      throw new Error("年龄必须是数字");
    }
    target[prop] = value;
    return true;
  }
});

(2) 实现私有属性和方法

const createUser = () => {
  const privateData = new WeakMap();

  return new Proxy({}, {
    get(target, prop) {
      if (prop.startsWith("_")) {
        throw new Error("无法访问私有属性");
      }
      return target[prop];
    }
  });
};

(3) 添加日志记录和调试功能

const logger = new Proxy({}, {
  get(target, prop) {
    console.log(`访问属性: ${prop}`);
    return target[prop];
  }
});

(4) 提供默认值和只读访问

const defaultSettings = new Proxy({}, {
  get(target, prop) {
    return prop in target ? target[prop] : "默认值";
  },
  set() {
    throw new Error("设置操作被禁止");
  }
});

(5) 实现惰性加载和缓存

const lazyObject = new Proxy({}, {
  get(target, prop) {
    if (!(prop in target)) {
      console.log(`初始化 ${prop}`);
      target[prop] = prop.toUpperCase();
    }
    return target[prop];
  }
});

(6) 解决 this 指向问题

const obj = {
  name: "Alice",
  greet() {
    return `Hello, ${this.name}`;
  }
};

const proxyObj = new Proxy(obj, {
  get(target, prop, receiver) {
    return typeof target[prop] === "function" ? target[prop].bind(target) : target[prop];
  }
});

const greet = proxyObj.greet;
console.log(greet()); // Hello, Alice

4.Object.defineProperty

Object.defineProperty() 允许直接在对象上定义新的属性,或者修改已有属性的特性(如可读写性、是否可枚举等)。

示例:

const person = {};

Object.defineProperty(person, "name", {
  value: "Alice",
  writable: false, // 不能修改
  enumerable: true,
  configurable: false
});

console.log(person.name); // Alice
person.name = "Bob"; // 失败,严格模式下会报错
console.log(person.name); // Alice

特点:

  • 只能加工 单个属性,不能监听整个对象。
  • 只能 定义静态的行为,不能动态处理对象属性的操作。
  • 不能拦截 删除新增属性函数调用

5. ProxyObject.defineProperty 详细对比

特性Object.definePropertyProxy
监听属性读取❌ 不支持✅ 支持 (get)
监听属性赋值✅ 支持 (set)✅ 支持 (set)
监听属性删除❌ 不支持✅ 支持 (deleteProperty)
监听属性存在性❌ 不支持✅ 支持 (has) (in 关键字)
监听对象新增属性❌ 不支持✅ 支持 (set)
监听函数调用❌ 不支持✅ 支持 (apply)
监听构造函数❌ 不支持✅ 支持 (construct)
监听整个对象❌ 需要对每个属性定义✅ 一次性监听整个对象
适用于数组或集合❌ 不适合✅ 适合
可扩展性❌ 需手动定义✅ 更强大,支持代理嵌套

相关文章:

  • 【redis】数据类型之bitmaps
  • 【H5自适应】高端科技类pbootcms网站模板 – 三级栏目、下载与招聘功能支持
  • Python自动化办公之Excel拆分
  • 真正通俗易懂的Langchain入门学习(六)
  • HDFS核对迁移的历史数据是否正确
  • python爬虫--简单登录
  • SpringBoot_基础
  • 树莓派上 基于Opencv 实现人脸检测与人脸识别
  • 通过 VBA 在 Excel 中自动提取拼音首字母
  • 互联网大厂中面试的高频计算机网络问题及详解
  • 20240824 美团 笔试
  • 3.3.3 VO-O语法- 语法算子(二)
  • 哈希表-两个数的交集
  • sql难点
  • 什么手机卡最便宜 怎么办手机卡最便宜
  • 【EXCEL】【VBA】处理GI Log获得Surf格式的CONTOUR DATA
  • AI驱动的广告制作革命:Icon如何实现从创意到成片的全流程自动化
  • OpenCV2D 特征框架 (22)人脸检测的一个类cv::FaceDetectorYN的使用
  • Sentinel——Spring Boot 应用接入 Sentinel 后内存开销增长计算方式
  • 1.攻防世界 unserialize3(wakeup()魔术方法、反序列化工作原理)
  • 盘锦市建设局网站地址/网络舆情监测专业
  • 陕西城乡建设厅网站/临沂网站seo
  • 品牌网站建设推广/云南今日头条新闻
  • wordpress 安装500/郑州seo线上推广系统
  • 什么网站专门做外贸批发/搜索引擎优化关键字
  • wordpress模板代码分析/seo网站系统