vue3发布以来,不少大佬在网上都对 vue2 和 vue3进行了全方位的对比,其中有一个很重要的改动是弃用 Object.defineProperty,使用了__性能更好__、__开发更加简便__的 Proxy。
Proxy 翻译成中文就是“代理”,从其名称我们就能大致了解其功能。下面让我们从几个角度重新了解一下proxy吧:
- Proxy 是什么
- Object.defineProperty 是什么,与 Proxy 的区别
- Proxy 有哪些好玩的场景
Proxy 是什么
Proxy 用于创建对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
const p = new Proxy(target, handler)
target:要使用 Proxy 包装的目标对象。
handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
handler 对象常用方法(点我查看 Proxy 文档):
- handler.get() 属性读取操作的捕捉器。
- handler.set() 属性设置操作的捕捉器。
- handler.apply() 函数调用操作的捕捉器。
- handler.construct() new 操作符的捕捉器。
/* 数字格式化 */
const target = {}
const handler = {
get: function(target, prop){
let str
const value = target[prop]
if( typeof(value) != 'number' ){
str = '--'
}else if( value < 1000 ){
str = value
}else if( value < 10000000 ){
str = `${parseInt(value/1000)}K`
}else{
str = `${parseInt(value/10000000)}KW`
}
return str
}
}
const p = new Proxy(target, handler)
p.a = 10000
console.log(p.a, target.a) //10K 10000
Object.defineProperty 是什么,与 Proxy 的区别
要了解 Proxy 与 Object.defineProperty 的区别,首先我们先回顾一下 Object.defineProperty 的用法。
Object.defineProperty() 用于对象属性的操作(新增或修改),并返回此对象。
Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象。
prop:要定义或修改的属性的名称或 Symbol 。
descriptor:要定义或修改的属性描述符。
descriptor 配置对象的常用属性(点我查看 Object.defineProperty 文档):
- configurable 为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
- value 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
- writable 为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
- get 属性的 getter 函数,如果没有 getter,则为 undefined。
- set 属性的 setter 函数,如果没有 setter,则为 undefined。
var o = {}
var bValue = 38
Object.defineProperty(o, "a", {
get() { return bValue; },
set(newValue) { bValue = newValue; },
configurable : true
})
o.a // 38
上面列举了 Proxy 和 Object.defineProperty 的使用方法和特性,通过对比可以看出这两种的区别主要体现在:
- __Proxy 代理整个对象,Object.defineProperty 只代理对象上的某个属性。__如果需要递归对象内的属性,Proxy 可以在调用时实现递归,Object.defineProperty 则需要在每个属性内重复执行相关操作,前者更加方便;
- __Proxy 对代理对象的监听更加丰富。__有且不限于以下场景:Proxy 可以监听对象新属性的定义(construct)和函数操作的调用(apply),而 Object.defineProperty 无法实现;
- Prxoy 代理对象会生成一个新的对象,不会修改被代理对象本身;Object.defineProperty 则是直接修改被代理对象的属性。
- __proxy 不兼容IE浏览器,而 __Object.defineProperty 则兼容IE8+。在IE浏览器环境下实现Proxy,需要额外引入 Proxy 兼容库。
Proxy 有哪些好玩的场景
通过对 Proxy 的了解,我们可以得知其有两个重要特性:数据监控、功能扩展。围绕这些特性我们可以将 Proxy 用于以下场景:
- 日志记录
对于用户行为、接口请求、异常抛出、可能出现内存占用过大的场景,我们希望对其进行记录,这个时候就可以使用 Proxy 充当中间件的角色,轻而易举实现日志功能。
- 校验模块抽离
如果要直接为对象的所有属性开发一个校验器,可能会让代码结构变得臃肿,使用 Proxy 则可以将校验器从核心逻辑分离出来自成一体。
- 文案格式化
计算数据和展示文案不一致,数据又可能同时在多处修改的时候;如果没有 Proxy,我们需要同时为数据定义两个变量进行存储,每次数据修改时都需要同时对变量进行修改,很容易出现逻辑遗漏;使用 Proxy 的话,我们就可以通过监听计算数据的变化,实时更新展示文案。
- 避免对象属性覆盖
我们对对象属性的新增往往没有任何监控手段,容易造成原有属性的覆盖;这种场景我们使用 Proxy 监控对象的 set 操作,如果发现新增的属性已存在就进行异常抛出,如果是对属性的赋值,我们直接对源对象进行操作即可。