Reflect 是 ES6 引入的一个内置对象,它提供了一组用于操作对象的静态方法。这些方法与对象的默认行为相对应,让元编程变得更加简洁和统一。

Reflect 的设计目标

1. 将语言内部方法函数化

将一些原本只能通过操作符完成的操作提供为函数形式:

// 传统方式
delete obj.prop
'prop' in obj
 
// Reflect 方式
Reflect.deleteProperty(obj, 'prop')
Reflect.has(obj, 'prop')

2. 与 Proxy 配合使用

Reflect 的方法与 Proxy 的拦截方法一一对应:

const handler = {
  get(target, prop, receiver) {
    console.log(`Getting ${prop}`)
    return Reflect.get(target, prop, receiver) // 调用默认行为
  },
  set(target, prop, value, receiver) {
    console.log(`Setting ${prop} = ${value}`)
    return Reflect.set(target, prop, value, receiver)
  }
}
 
const proxy = new Proxy({}, handler)

3. 更合理的返回值

提供布尔值返回而不是抛出异常:

// Object.defineProperty 失败时抛出异常
try {
  Object.defineProperty(obj, 'prop', descriptor)
} catch (e) {
  // 处理错误
}
 
// Reflect.defineProperty 返回布尔值
if (Reflect.defineProperty(obj, 'prop', descriptor)) {
  // 成功
} else {
  // 失败
}

主要方法详解

属性操作

const obj = { name: 'Vue', version: 3 }
 
// 获取属性
Reflect.get(obj, 'name') // 'Vue'
 
// 设置属性
Reflect.set(obj, 'author', 'Evan You') // true
 
// 检查属性存在
Reflect.has(obj, 'name') // true
 
// 删除属性
Reflect.deleteProperty(obj, 'version') // true
 
// 获取所有属性键
Reflect.ownKeys(obj) // ['name', 'author']

属性描述符操作

const obj = {}
 
// 定义属性
Reflect.defineProperty(obj, 'prop', {
  value: 42,
  writable: true,
  enumerable: true,
  configurable: true
}) // true
 
// 获取属性描述符
Reflect.getOwnPropertyDescriptor(obj, 'prop')
// { value: 42, writable: true, enumerable: true, configurable: true }

原型操作

const obj = {}
const proto = { inherited: true }
 
// 设置原型
Reflect.setPrototypeOf(obj, proto) // true
 
// 获取原型
Reflect.getPrototypeOf(obj) === proto // true

对象扩展性

const obj = {}
 
// 检查是否可扩展
Reflect.isExtensible(obj) // true
 
// 阻止扩展
Reflect.preventExtensions(obj) // true
 
Reflect.isExtensible(obj) // false

函数调用和构造

function greet(name) {
  return `Hello, ${name}!`
}
 
// 调用函数
Reflect.apply(greet, null, ['World']) // 'Hello, World!'
 
// 构造对象
function Person(name) {
  this.name = name
}
 
const person = Reflect.construct(Person, ['Alice'])
// 等同于 new Person('Alice')

实际应用场景

1. 创建安全的属性访问

function safeGet(obj, prop) {
  try {
    return Reflect.get(obj, prop)
  } catch (e) {
    return undefined
  }
}

2. 实现观察者模式

function createObservable(target) {
  const observers = new Set()
  
  return new Proxy(target, {
    set(obj, prop, value, receiver) {
      const result = Reflect.set(obj, prop, value, receiver)
      if (result) {
        observers.forEach(observer => observer(prop, value))
      }
      return result
    },
    
    addObserver(observer) {
      observers.add(observer)
    }
  })
}

3. 属性验证

function createValidatedObject(target, validators = {}) {
  return new Proxy(target, {
    set(obj, prop, value, receiver) {
      const validator = validators[prop]
      if (validator && !validator(value)) {
        throw new Error(`Invalid value for ${prop}`)
      }
      return Reflect.set(obj, prop, value, receiver)
    }
  })
}
 
const user = createValidatedObject({}, {
  age: value => typeof value === 'number' && value >= 0
})
 
user.age = 25 // 成功
user.age = -5 // 抛出错误

Reflect vs Object 方法对比

ReflectObject区别
Reflect.defineProperty()Object.defineProperty()Reflect 返回布尔值,Object 返回对象或抛出异常
Reflect.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor()基本相同
Reflect.getPrototypeOf()Object.getPrototypeOf()Reflect 对非对象参数会抛出 TypeError
Reflect.ownKeys()Object.getOwnPropertyNames() + Object.getOwnPropertySymbols()Reflect 返回所有键(包括 Symbol)

总结

Reflect 提供了一套统一、函数式的 API 来操作对象,特别适合:

  1. 元编程:动态操作对象属性和行为
  2. 与 Proxy 配合:实现代理对象的默认行为
  3. 函数式编程:将操作符转换为函数调用
  4. 错误处理:通过返回值而不是异常来处理失败情况

Reflect 是现代 JavaScript 元编程的重要工具,在框架开发和高级应用中发挥着重要作用。