《十二》ES6+ 中的 Proxy

本文详细介绍了ES6中新增的Proxy类,展示了如何利用Proxy进行对象操作的拦截和改写,对比了Object.defineProperty()和Proxy在实现响应式原理上的优劣,并通过实例演示了Proxy的各种捕获器使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES6 中新增了一个 Proxy 类,Proxy 的原意是代理,用在这里表示由它来代理某些操作,可以译为代理器。可以理解成,在目标对象之前架设一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

通过 Object.defineProperty() 也可以实现监听对象属性的操作 。

let person = {name: 'Lee'}
let _name = person.name
Object.defineProperty(person, 'name', {
	get: function() {
		console.log('监听获取值')
		return _name
	},
	set: function(newVal) {
		console.log('监听设置值')
		_name = newVal
	}
})

console.log(person.name)
person.name = 'Mary'

请添加图片描述
但是是存在弊端的:首先,Object.defineProperty() 设计的初衷并不是为了去监听一个完整对象中所有的属性;其次,如果想监听更加丰富的操作,比如新增属性、删除属性、是否存在属性等,是无法做到的。

Vue2 就是通过 Object.defineProperty() 来实现响应式原理的,但在 Vue3 中改为了通过 Proxy 来实现响应式原理。

创建 Proxy 实例:

如果想要监听一个对象的相关操作,可以先通过 new Proxy() 来创建一个代理对象,之后对目标对象的所有操作,都通过代理对象来完成,代理对象可以监听对目标对象对象进行了哪些操作,并自动反馈给目标对象。

new Proxy() 接收两个参数,第一个参数表示所要拦截的目标对象;第二个参数是一个配置对象,用来定制代理行为,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。

var target = {
	name: ’Lee',
};
var handler = {
  get: function(target, propKey) {
    return 35
  }
}
// 创建一个代理对象
var proxy = new Proxy(target,handler)

// 对目标对象的所有操作,都要通过代理对象来进行,代理对象会自动反馈给目标对象
proxy.name // 35
proxy.age // 35

如果配置对象是一个空对象,没有设置任何拦截,那就等同于直接通向源对象,访问代理对象就等同于访问目标对象。

var target = {
	name: ’Lee',
};
var handler = {};
var proxy = new Proxy(target, handler)
proxy.name = 'Lee'
target.name // Lee

Proxy.revocable()

Proxy.revocable() 方法返回一个可取消的 Proxy 实例。该方法返回一个对象,该对象的 proxy 属性是 Proxy 实例;revoke 属性是一个函数,可以取消 Proxy 实例。

let target = {
	foo: 123,
};
let handler = {};

let {proxy, revoke} = Proxy.revocable(target, handler);

proxy.foo = 123;
proxy.foo // 123

revoke();
proxy.foo // TypeError: Revoked

Proxy.revocable() 的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,但是一旦访问结束就要收回代理权,不允许再次访问。

this 问题:

虽然 Proxy 可以代理针对目标对象的访问,但它并不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为完全一致。

主要原因就是在 Proxy 代理的情况下,对象内部的 this 关键字会指向 Proxy 代理。

const target = {
  m: function () {
    console.log(this === proxy);
  }
};
const handler = {};

const proxy = new Proxy(target, handler);

target.m() // false
proxy.m()  // true

上面代码中,一旦 proxy 代理 target,后者内部的 this 就是指向 proxy 而不是 target。

捕获器:

如果想要监听某些具体的操作,可以在配置对象中添加对应的捕获器。

  1. get():属性读取操作的捕获器。用来监听读取属性的操作,默认会接收到三个参数,依次为目标对象,被获取的属性名 key 和代理对象。
    let person = {name: 'Lee'}
    let proxy = new Proxy(person, {
    	// 读取属性时自动执行
    	get: function(target, key, receiver){
    		return target[key]
    	}
    })
    
    proxy.name //Lee
    
  2. set():属性设置操作的捕获器。用来监听设置属性的操作,默认会接收到四个参数,依次为目标对象、被设置的属性名 key、被设置的属性值和代理对象。
    let person = {name: 'Lee'}
    let proxy = new Proxy(person, {
    	get: function(target, key, receiver){
    		return target[key]
    	},
    	// 设置属性时自动执行
    	set: function(target, key, value, receiver){
    		target[key] = value
    	},
    })
    
    proxy.name = 'Mary'
    proxy.name // Mary
    
  3. deleteProperty():delete 操作符的捕获器。用来监听删除属性的操作。
    let person = { name: 'Lee' }
    let proxy = new Proxy(person,  {
      // 删除属性时自动执行
      deleteProperty (target, key) {
        delete target[key]
      }
    })
    delete proxy.name
    
  4. has():in 操作符的捕获器。用来监听判断属性是否存在的操作。
  5. apply():函数调用操作的捕获器。用来监听函数的调用。
  6. construct():new 操作符的捕获器。用来监听 new 操作。
  7. ownKeys()Object.getOwnPropertyNames()Object.getOwnPropertySymbols() 方法的捕获器。
  8. defineProperty()Object.defineProperty() 方法的捕获器。
  9. getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor() 方法的捕获器。返回值是一个属性描述对象或者 undefined。
  10. getPropertyOf()Object.getPropertyOf() 方法的捕获器。用来监听获取对象的隐式原型。返回值必须是对象或者 null,否则报错。
  11. setPropertyOf()Object.setPropertyOf() 方法的捕获器。用来监听设置对象的隐式原型。返回值必须是布尔值,否则会被自动转为布尔值。
  12. isExtensible()Object.isExtensible() 方法的捕获器。返回值只能是布尔值,否则会被自动转为布尔值。
  13. preventExtensions()Object.preventExtensions() 方法的捕获器。返回值只能是布尔值,否则会被自动转为布尔值。
<think>嗯,用户问的是“es6+什么意思”,首先我需要确认用户对ES6的了解程度。可能他们听说过ES6,但不太清楚具体指的是什么,或者后面的“+”号代表什么。 首先,ES6是ECMAScript 2015的简称,是JavaScript的一个重要版本。用户可能知道JavaScript,但可能不清楚版本之间的差异。需要解释清楚ES6的全称和发布时间,以及它带来的重大更新。 接下来,“+”号可能表示ES6之后的版本,比如ES7、ES8等。用户可能想了解这些后续版本的新特性,或者想知道“ES6+”作为一个整体术语在开发中的意义。这时候需要说明ES6+通常指的是ES6及之后的版本,涵盖了从2015年至今的JavaScript新特性。 用户可能是在学习前端开发时遇到了这个术语,或者在技术文档中看到,想要了解其重要性。需要强调ES6+对现代JavaScript开发的影响,比如模块化、箭头函数、类、异步处理等,这些都是现代开发中的常用特性。 可能用户的实际需求是想要了解学习ES6+的必要性,或者是在项目中使用ES6+的好处。这时候需要分点列出ES6+的关键特性,并说明每个特性如何改进开发效率和代码质量。 另外,用户可能对版本命名方式有疑问,为什么从ES6之后改为按年份命名。需要简单解释ECMAScript的版本发布策略变化,帮助用户理解ES2015、ES2016等名称的由来。 最后,用户可能想知道如何开始学习ES6+,或者有哪些资源推荐。不过根据当前问题,可能不需要展开,但可以提到掌握ES6+对前端开发者是必备技能,鼓励深入学习。 需要确保回答结构清晰,分点明确,使用示例帮助理解,同时语言简洁,避免技术术语过于复杂。另外,用户之前关于作用域的问题中,提到了JavaScript的作用域类型,可能用户有JS基础,因此可以适当联系之前的知识点,比如块级作用域与let/const的关系,属于ES6的内容,加强连贯性。 总结回答的结构:定义ES6+,解释版本演变,关键特性,重要性,最后总结其意义。确保每个部分都有具体例子,比如箭头函数、解构赋值等,让用户更直观地理解。</think>### 一、ES6+ 的定义 **ES6+** 是 **ECMAScript 2015(ES6)及后续版本** 的统称,代表从2015年开始发布的现代JavaScript语言标准。ES6是JavaScript自1997年标准化以来 **最重要的升级**,而“+”符号表示其后续版本(如ES7/ES8/ES9等,现按年份命名为ES2016+)。 --- ### 二、版本演进与命名规则 1. **ES6ES2015)** - 发布于2015年,原名ES6,后统一改为按年份命名(ECMAScript 2015)。 - **里程碑式更新**,引入了类、模块化、箭头函数等核心特性。 2. **ES2016+** - 2016年起每年发布新版本,命名规则改为 **ES+年份**(如ES2016ES2023)。 - **增量更新**,逐步添加新功能(如`async/await`、可选链操作符`?.`)。 --- ### 三、ES6+ 的核心特性(部分示例) #### 1. 声明变量:`let` 与 `const` - 替代`var`,支持 **块级作用域**: ```javascript if (true) { let x = 10; // 仅在块内有效 const y = 20; // 常量 } ``` #### 2. 箭头函数(Arrow Functions) - 简化函数语法,自动绑定外层`this`: ```javascript // 传统函数 const sum = function(a, b) { return a + b; }; // 箭头函数 const sum = (a, b) => a + b; ``` #### 3. 解构赋值(Destructuring) - 从数组或对象中提取值: ```javascript // 数组解构 const [a, b] = [1, 2]; // 对象解构 const { name, age } = { name: "Alice", age: 25 }; ``` #### 4. 类(Class) - 提供面向对象的语法糖: ```javascript class Person { constructor(name) { this.name = name; } greet() { console.log(`Hello, ${this.name}!`); } } ``` #### 5. 模块化(Modules) - 支持`import`/`export`管理代码: ```javascript // math.js export const add = (a, b) => a + b; // app.js import { add } from './math.js'; ``` #### 6. 异步处理:`Promise` 与 `async/await` - 解决回调地狱,简化异步操作: ```javascript async function fetchData() { const res = await fetch('https://api.example.com'); const data = await res.json(); return data; } ``` --- ### 四、ES6+ 的重要性 1. **开发效率提升**:语法更简洁(如箭头函数、模板字符串)。 2. **代码可维护性增强**:模块化、类等特性支持大型项目。 3. **功能现代化**:`Promise`、`Proxy`等特性解决传统JS痛点。 4. **浏览器与Node.js全面支持**:现代环境已原生支持ES6+。 --- ### 五、ES6+ 的兼容性处理 若需兼容旧浏览器(如IE11),可通过工具转换代码: 1. **Babel**:将ES6+代码转译为ES5语法。 2. **Polyfill**:补充缺失的API(如`Promise`)。 --- ### 六、总结 - **ES6+** = ES2015及后续版本,代表现代JavaScript标准。 - **核心价值**:语法简化、功能增强、工程化支持。 - **学习建议**:掌握ES6+是前端开发的必备基础,建议从`let/const`、箭头函数、解构赋值等高频特性入手。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值