Proxy是什么,和defineProperty有什么区别

在背八股的时候,大家都会背上几句,vue2是通过Object.defineProperty来实现响应式原理的,而vue3是通过Proxy来实现的。

然后看上里面的几种方法,并没有过多的去深究。当然我也差不多啦,所以特地的去看了一下,那么废话少说。

1. Proxy是什么

Proxy 是 ES6 引入的特性,可以创建一个对象的代理,拦截并自定义对象的基本操作(如属性访问、赋值、函数调用等)。

基本语法

创建proxy:

js 复制代码
const proxy = new Proxy(target, handler);
  • target:要代理的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理))。
  • handler:一个对象,内部属性通常为函数,其函数定义了执行各种操作时的行为。

例子:

js 复制代码
const obj={
    name:'lihua',
    age:18
}

const handler={
    get(obj,prop){
        console.log('触发get');
        return prop in obj? obj[prop] : 233
    },
    set(obj,prop,value){
        console.log('触发set');
        obj[prop]=value
        return ture
    },
}

const proxy=new Proxy(obj,handler)

console.log(proxy.name);// 触发get lihua
console.log(proxy.age);// 触发get 18

proxy.name='zhangsan'// 触发set
console.log(proxy.name);//触发get zhangsan

这里set不返回bool值会报错

从中还可以看出,Proxy代理的是整个对象,而不是对象的某个属性。

2.proxy的功能

支持proxy这些功能的当然就是陷阱函数,可以对不同的操作进行拦截。

除了get和set,还有很多种不同的陷阱函数,详细的可以去mdn上看,这里列举几种常见的

has拦截in操作符

参数:

  • target :被代理的目标对象。
  • prop :检查是否存在的属性名(可以是字符串或 Symbol)。

prop的含义根据陷阱函数不同而不同,其他参数还有很多,如value表示属性值等

js 复制代码
const obj={
    name:'lihua',
    age:18
}

const handler={
    has(target,prop){
        console.log('触发has');
        return Reflect.has(target,prop)//Reflect.has(target,prop)会返回true或者false
    }
}

const proxy=new Proxy(obj,handler)
console.log("name" in proxy)// 触发has true

apply拦截函数调用

参数:

  • target :被代理的目标函数。
  • thisArg :调用时的 this 值。
  • argumentsList :传递给函数的参数数组。
js 复制代码
function sum(a, b) {
    return a + b;
  }
  
  const handler = {
    apply(target, thisArg, argumentsList) {
      console.log(`触发apply`);
      return Reflect.apply(target, thisArg, argumentsList);
    }
  };
  
  const proxy = new Proxy(sum, handler);
  
  console.log(proxy(2, 3)); // 触发apply 5

其他的陷阱函数还有deleteProperty(target, prop)拦截delete,construct(target, args)拦截new操作符等等

3. 与defineProperty的区别

可动态添加属性

defindeProperty只能对已经存在的属性进行拦截,无法动态拦截新增的属性

Proxy可以:

js 复制代码
const obj = {}

const handler = {
    set(target,prop,value){
        console.log('触发set');
        target[prop]=value
        return true
    }
}

const proxy = new Proxy(obj, handler)

proxy.name='zhangsan'// 触发set
console.log(proxy.name);// zhangsan

可以拦截更多操作

defineProperty只能拦截getset,无法拦截其他操作 但是Proxy提供了多种陷阱,可以拦截更多操作

  • 属性访问(get)、赋值(set
  • 删除属性(deleteProperty
  • 检查属性是否存在(has
  • 构造函数调用(construct
  • 函数调用(apply

数组的支持

defineProperty不能对pushpop,等操作以及数组长度变化等进行拦截 但是Proxy可以拦截数组的所有操作,包括长度变化和索引访问

js 复制代码
const arr = [];
const proxy = new Proxy(arr, {
  set(target, prop, value) {
    console.log('触发set');
    target[prop] = value;
    return true;
  }
});

proxy.push(10); // 触发set
console.log(proxy); // 触发set 10
proxy.push(20)//触发set
console.log(proxy); // 触发set 10,20
proxy.pop()//触发set
console.log(proxy);// 触发set 10

4.不足

兼容性问题

Proxy 是 ES6 引入的新特性,在一些老旧环境中可能不被支持(如 IE 浏览器)。

无法代理原始值

Proxy 只能代理对象(包括数组、函数等),无法直接代理原始值(如数字、字符串、布尔值),如果需要代理原始值,可以将其包装在一个对象中。

相关推荐
AI大模型顾潇26 分钟前
[特殊字符] 本地大模型编程实战(29):用大语言模型LLM查询图数据库NEO4J(2)
前端·数据库·人工智能·语言模型·自然语言处理·prompt·neo4j
九月TTS1 小时前
TTS-Web-Vue系列:Vue3实现内嵌iframe文档显示功能
前端·javascript·vue.js
爱编程的小学究1 小时前
【node】如何把包发布到npm上
前端·npm·node.js
我爱加班、、1 小时前
Chrome安装最新vue-devtool插件
javascript·vue.js·chrome·vue-devtool
weixin_473894771 小时前
前端服务器部署分类总结
前端·网络·性能优化
LuckyLay2 小时前
React百日学习计划-Grok3
前端·学习·react.js
澄江静如练_2 小时前
小程序 存存上下滑动的页面
前端·javascript·vue.js
互联网搬砖老肖2 小时前
Web 架构之会话保持深度解析
前端·架构
m0_513962532 小时前
vue-ganttastic甘特图label标签横向滚动固定方法
javascript·vue.js·甘特图
菜鸟una2 小时前
【taro3 + vue3 + webpack4】在微信小程序中的请求封装及使用
前端·vue.js·微信小程序·小程序·typescript·taro