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

相关推荐
bin91539 分钟前
DeepSeek 助力 Vue 开发:打造丝滑的 复选框(Checkbox)
前端·javascript·vue.js·前端框架·ecmascript·deepseek
柯南二号35 分钟前
【Android】用 chrome://inspect/#devices 调试H5页面
android·前端·chrome
程序员黄同学1 小时前
请谈谈 React 中的状态管理,如何使用 Context API 和 Redux 进行状态管理?
前端·react.js·前端框架
林涧泣1 小时前
【Uniapp-Vue3】实现隐式自动注册登录及config配置
前端·vue.js·uni-app
起个破名想半天了2 小时前
Web自动化之Selenium execute_script函数常用JS脚本
javascript·python·selenium·自动化
AlgorithmAce2 小时前
解决npm/yarn等包管理工具在vscode中使用出现系统禁止运行脚本的情况
前端·npm·node.js
bin91532 小时前
DeepSeek 助力 Vue 开发:打造丝滑的分割线(Divider)
前端·javascript·vue.js·前端框架·ecmascript·deepseek
超级无敌谢大脚2 小时前
前端包管理工具进化论:npm vs yarn vs pnpm 深度对比
前端·npm·node.js
羊小猪~~2 小时前
基于C++“简单且有效”的“数据库连接池”
java·开发语言·前端·数据库·c++·后端·adb
TE-茶叶蛋2 小时前
利用 Vue 3 + Vite + Element UI Plus 结合 Service Worker 实现版本管理
前端·vue.js