Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • reactivity响应式

    • ref
    • reactive
    • 基础对象的代理
    • 数组代理的方法
    • 集合对象的代理
    • Reflect和Proxy详解
      • 概览
      • 正文
        • Proxy
        • handler实例方法
        • Reflect
        • Reflect静态方法
    • 依赖的收集与触发
    • effectScope解析
    • effect解析
    • reactive响应式依赖的收集与触发监听
    • 批量更新实现
    • ReactiveEffect类介绍
    • computed
  • 5.18源码学习》
  • reactivity响应式
东流
2025-08-14
目录

Reflect和Proxy详解

# 概览

Proxy和 Reflect是都是在ES6中引入的新对象。它们也是 vue3 实现响应式的基础。这篇文章会深入理解分析这两个重要的角色。

# 正文

# Proxy

Proxy对象用于创建一个对象的代理,从而实现对目标对象的访问拦截和修改(如属性查找、赋值、枚举和函数调用),修改这些操作的默认行为。

  • 语法:new Proxy(target, handler)

target: 需要代理的目标对象(可以是任何类型,包括原生对象)

handler: 一个对象,其属性是当执行一个操作时定义代理的行为的函数。

# handler实例方法

参照 MDN 文档,handler可以如下 13 种方法

  • **handler.apply(target,thisArg,args)

handler.apply用于拦截函数的调用、call和apply操作,返回一个值。如果没有定义该方法,那么调用函数时会直接调用目标函数。

  • handler.construct(target,args) 用于拦截构造函数new操作符的调用

  • handler.defineProperty(target,key,descriptor)

handler.defineProperty用于拦截对象Object.defineProperty()操作,返回一个布尔值。如果返回false或者报错,则定义属性操作无效。

  • handler.deleteProperty(target,key)

handler.deleteProperty用于拦截对对象属性的delete操作,返回一个布尔值。如果返回false或者报错,则删除操作无效。

  • handler.get(target,key,receiver)

handler.get用于拦截对象某个属性的读取操作,返回该属性的值。如果属性不存在,则返回undefined。如果属性部署了getter,那么getter的this是指向第三个参数receiver,若参数receiver省略,则this默认指向target。

  • handler.getOwnPropertyDescriptor(target,key)

handler.getOwnPropertyDescriptor用于拦截Object.getOwnPropertyDescriptor()操作,返回属性描述对象Descriptor或者undefined。

  • handler.getPrototypeOf(target)

handler.getPrototypeOf(target)用于拦截获取对象原型,会拦截如下操作:Object.prototype.__prototype_、Object.prototype.isPrototypeOf()、Object.getPrototype()、Reflect.getPrototypeOf()和instanceof等操作。

handler.getPrototypeOf的返回值必须是对象或者null,否则会报错。若target是不可扩展的,则必须返回目标对象的原型对象。

  • handler.has() 拦截in操作符

  • handler.isExtensible(target)

handler.isExtensible(target)用于拦截Object.isExtensible()操作,返回一个布尔值,并且该布尔值与target的isExtensible属性值相同,否则会报错。

  • handler.ownKeys(target) handler.ownKeys方法用于拦截对对象自身属性的读取操作返回一个数组;如Object.getOwnPropertyNames()和Object.getOwnPropertySymbols(),Object.keys()和for...in等

  • handler.preventExtensions(target)

handler.preventExtensions方法用于拦截Object.preventExtensions(),该方法必须返回一个布尔值,否则会被自动转为布尔值。

  • handler.set(target,key,value,receiver)

handler.set用于拦截对象某个属性的赋值操作,返回一个布尔值。如果赋值成功,则返回true;否则,返回false。如果属性部署了setter,那么setter的this是指向第四个参数receiver,若参数receiver省略,则this默认指向target。

  • handler.setPrototypeOf(target,prototype)

handler.setPrototypeOf方法主要用于拦截Object.setPrototypeOf()方法,返回一个布尔值。如果设置成功,则返回true;否则,返回false。

# Reflect

Reflect对象是ES6为了操作对象而提供的新 API,它提供了拦截 JavaScript 操作对象的方法。这些方法与Proxy的handler方法相对应。

# Reflect静态方法

Reflect对象一共有 13 个静态方法,大部分与Object对象的同名方法的作用相同,并且与Proxy对象的方法相对应。

  • Reflect.apply(func,thisArg,args)

Reflect.apply方法用于调用函数,返回函数执行结果。该方法与Function.prototype.apply()方法功能相同,但是Reflect.apply方法的参数是func函数、this对象和参数数组,返回值是函数执行结果。

  • Reflect.construct(target,args)

Reflect是一个静态类,不能实例化,也不能被继承,因此无法使用new操作符。但是Reflect.construct方法可以用来调用构造函数。

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

const p = Reflect.construct(Person, ["Bob", 18]);
console.log(p); // Person {name: '张三', age: 18}

//等价于
const p = new Person("Bob", 18);

1
2
3
4
5
6
7
8
9
10
11
12
13
  • Reflect.get(target,name,receiver)

Reflect.get用于查找target对象的name属性,返回该属性的值。如果name属性不存在,则返回undefined。如果target的name属性部署了getter,那么getter的this是指向第三个参数receiver,若参数receiver省略,则this默认指向target。

const studentA = {
  name: "Bob",
  age: 18,
  get info() {
    return `${this.name} is ${this.age}`;
  },
};

const studentB = {
  name: "Alice",
  age: 19,
};

console.log(Reflect.get(studentA, "info")); // Bob is 18

console.log(Reflect.get(studentA, "info", studentB)); // Alice is 19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • Reflect.set(target,name,value,receiver)

Reflect.set用于设置target对象的name属性等于value。如果name属性设置了setter,则setter的this绑定receiver。

const studentA = {
  name: "Bob",
  set setSex(value) {
    this.sex = value;
  },
};

const studentB = {
  name: "Alice",
};

Reflect.set(studentA, "setSex", "male");
console.log(studentA.sex); // male
Reflect.set(studentA, "setSex", "female", studentB);
console.log(studentA.sex, studentB.sex); // male,female
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • Reflect.defineProperty(target,name,desc)

Reflect.defineProperty方法基本等同于Object.defineProperty,返回一个布尔值。如果操作失败,会抛出一个错误。Object.defineProperty会逐渐被废弃。

另外Reflect.defineProperty的第一个参数必须是对象,否则会抛出错误。

Reflect.defineProperty({}, "name", {
  value: "Bob", // 值
  writable: true, // 是否可写
  enumerable: true, // 是否可枚举
  configurable: true, // 是否可配置
});
1
2
3
4
5
6
  • Reflect.deleteProperty(target,name)

Reflect.deleteProperty方法用于删除对象的属性,返回一个布尔值。如果删除成功,返回true;如果删除失败,返回false。

同理,若Reflect.deleteProperty的第一个参数不是对象,也会抛出错误。

  • Reflect.has(target,name)

Reflect.has方法对应name in target的操作。如果target对象继承了name属性,返回true;否则返回false。相比name in obj写法,Reflect.has是函数的形式,且心智负担很小。

  • Reflect.ownKeys(target)

Reflect.ownKeys方法用于返回对象的所有属性,包括不可枚举属性。它的返回值是一个数组,数组的成员是字符串,每个字符串对应一个属性名。

Reflect.ownKeys基本等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)),但它是一个静态方法,不需要实例化。

同理,若Reflect.ownKeys的第一个参数不是对象,也会抛出错误。

Reflect.ownKeys({
  name: "Bob",
  age: 18,
  [Symbol("symbol")]: "symbol",
});

// ['name', 'age', Symbol(symbol)]
1
2
3
4
5
6
7
  • Reflect.isExtensible(target)

Reflect.isExtensible方法对应Object.isExtensible方法,返回一个布尔值,表示当前对象是否可扩展。

同理,若Reflect.isExtensible的第一个参数不是对象,也会抛出错误。

在某些情况下,Reflect.isExtensible(obj)会返回false,如对象obj被Object.preventExtensions(obj)、Object.seal(obj)、Object.freeze(obj)等处理后,会返回false。另外,JS 某些内置对象也是不可扩展对象,如Math、JSON。

总结如下:

方法/状态 isExtensible 能否添加属性 能否删除属性 能否修改值
默认对象 ✅ true ✅ 是 ✅ 是 ✅ 是
Object.preventExtensions() ❌ false ❌ 否 ✅ 是 ✅ 是
Object.seal() ❌ false ❌ 否 ❌ 否 ✅ 是
Object.freeze() ❌ false ❌ 否 ❌ 否 ❌ 否
  • Reflect.preventExtensions(target)

Reflect.preventExtensions(target)对应Object.preventExtension方法,用于让一个对象变为不可扩展,返回一个布尔值,表示是否操作成功。

  • Reflect.getOwnPropertyDescriptor(target,name)

Reflect.getOwnPropertyDescriptor(target,name)对应Object.getOwnPropertyDescriptor方法,用于获取对象的属性描述符,返回一个PropertyDescriptor对象。

let p={}
Reflect.defineProperty(p,'name',{
    value:"Jinus",
    enumerable:false,
    writable:true,
    configurable:true,
})

console.log(Reflect.getOwnPropertyDescriptor(p,'name')) 
// {value:"Jinus",enumerable:false,writable:true,configurable:true,}

console.log(Reflect.getOwnPropertyDescriptor(p,'age')) 
// undefined  
1
2
3
4
5
6
7
8
9
10
11
12
13
  • Reflect.getPrototypeOf(target)

Reflect.getPrototypeOf方法对应Object.getPrototypeOf,用于读取对象的__proto__属性,返回对象的原型。若参数target不是对象,Reflect.getPrototypeOf会报错,而Object.getPrototypeOf会将target转为对象,再获取该对象的__prototype。

  • Reflect.setPrototypeOf(target,prototype)

Reflect.setPrototypeOf方法对应Object.setPrototypeOf,用于设置对象的原型prototype,返回一个布尔值,表示是否操作成功。

若参数target不是对象,Reflect.setPrototypeOf会报错,而Object.setPrototypeOf会返回target自身。特殊情况下,target为null或undefined,Reflect.setPrototypeOf会何Object.setPrototypeOf都会报错。

编辑 (opens new window)
上次更新: 2025/08/19, 10:14:47
集合对象的代理
依赖的收集与触发

← 集合对象的代理 依赖的收集与触发→

最近更新
01
computed
08-26
02
ReactiveEffect类介绍
08-26
03
批量更新实现
08-25
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式