Learning Book

Reflect API

Reflect API

Reflect — объект со статическими методами, соответствующими каждой ловушке Proxy. Он предоставляет «дефолтное» поведение операций.

Зачем нужен Reflect

Без Reflect в ловушке легко сломать цепочку прототипов или потерять receiver:

// НЕПРАВИЛЬНО — нарушает цепочку receiver
const bad = new Proxy({}, {
  get(target, prop) {
    return target[prop] // target[prop] игнорирует receiver
  }
})

// ПРАВИЛЬНО — передаём receiver, сохраняем прототипную цепочку
const good = new Proxy({}, {
  get(target, prop, receiver) {
    return Reflect.get(target, prop, receiver) // корректно!
  }
})

Методы Reflect

Каждый метод Reflect соответствует ловушке Proxy:

// Аналогично target[prop]
Reflect.get(target, prop, receiver)

// Аналогично target[prop] = value
Reflect.set(target, prop, value, receiver)

// Аналогично prop in target
Reflect.has(target, prop)

// Аналогично delete target[prop]
Reflect.deleteProperty(target, prop)

// Аналогично target.apply(thisArg, args)
Reflect.apply(fn, thisArg, args)

// Аналогично new Cls(...args)
Reflect.construct(Cls, args)

// Аналогично Object.keys / for...in
Reflect.ownKeys(target)
Правило большого пальца: в теле ловушки Proxy всегда используй соответствующий Reflect-метод для делегирования к оригинальному объекту. Это гарантирует корректное поведение с прототипами и дескрипторами.

Пример: корректный логирующий прокси

function createLogger(target, name = 'obj') {
  return new Proxy(target, {
    get(target, prop, receiver) {
      const value = Reflect.get(target, prop, receiver)
      if (typeof value !== 'function') {
        console.log(`${name}.${prop} → ${JSON.stringify(value)}`)
      }
      return value
    },
    set(target, prop, value, receiver) {
      console.log(`${name}.${prop} = ${JSON.stringify(value)}`)
      return Reflect.set(target, prop, value, receiver)
    }
  })
}

const user = createLogger({ name: 'Алиса' }, 'user')
user.name         // лог: "user.name → "Алиса""
user.name = 'Боб' // лог: "user.name = "Боб""

Reflect.apply vs Function.prototype.apply

// Старый способ
Function.prototype.apply.call(Math.max, null, [1, 2, 3]) // 3

// С Reflect — чище и безопаснее
Reflect.apply(Math.max, null, [1, 2, 3]) // 3