Using the brainstorming skill because this is a frontend demo creation request. Proxy Is for Proxies. What Is Reflect For?

Proxy Is for Proxies. What Is Reflect For?

A hands-on set of small demos showing where Reflect mirrors old syntax, where return values help, and why Proxy handlers often delegate to Reflect.

1. Reflect.get and Reflect.set Mirror Property Access

Code:
const input = document.querySelector('#basicInput');
const output = document.querySelector('#basicOutput');
const directButton = document.querySelector('#basicDirect');
const reflectButton = document.querySelector('#basicReflect');
const readButton = document.querySelector('#basicRead');

directButton.addEventListener('click', () => {
  input.value = 'direct assignment';
  output.textContent = "input.value = 'direct assignment'";
});

reflectButton.addEventListener('click', () => {
  Reflect.set(input, 'value', 'Reflect.set value');
  output.textContent = "Reflect.set(input, 'value', 'Reflect.set value')";
});

readButton.addEventListener('click', () => {
  output.textContent =
    `Reflect.get(input, 'value') -> ${Reflect.get(input, 'value')}`;
});
Result:
Waiting for an action.

2. Reflect.defineProperty Can Redefine DOM Behavior

Code:
const input = document.querySelector('#descriptorInput');
const output = document.querySelector('#descriptorOutput');
const setButton = document.querySelector('#descriptorSet');
const clearButton = document.querySelector('#descriptorClear');
const props = Reflect.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');

Reflect.defineProperty(input, 'value', {
  ...props,
  set(value) {
    let oldValue = this.value;
    props.set.call(this, value);

    if (oldValue !== value) {
      this.dispatchEvent(new CustomEvent('change'));
    }
  }
});

input.addEventListener('change', () => {
  output.append('It changed~ ');
});

setButton.addEventListener('click', () => {
  input.value = 'zhangxinxu';
});

clearButton.addEventListener('click', () => {
  input.value = '';
  output.textContent = '';
});
Result:
No change event yet.

3. Reflect.set Returns Whether Assignment Worked

Code:
const input = document.querySelector('#readonlyTypeInput');
const output = document.querySelector('#readonlyTypeOutput');
const runButton = document.querySelector('#readonlyTypeRun');

Object.defineProperty(input, 'type', {
  configurable: true,
  get() {
    return this.getAttribute('type') || 'text';
  }
});

runButton.addEventListener('click', () => {
  const assignmentResult = (input.type = 'number');
  const reflectResult = Reflect.set(input, 'type', 'number');

  output.textContent = [
    `input.type = 'number' -> ${assignmentResult}`,
    `Reflect.set(input, 'type', 'number') -> ${reflectResult}`,
    `Actual input.type -> ${input.type}`
  ].join('\n');
});
Result:
The type getter currently reports text.

4. Reflect.set Avoids Strict-Mode Interruption

Code:
const direct = document.querySelector('#frozenDirect');
const reflect = document.querySelector('#frozenReflect');
const output = document.querySelector('#frozenOutput');

direct.addEventListener('click', () => {
  output.textContent = '';

  try {
    (function () {
      'use strict';

      var frozen = { 1: 81 };
      Object.freeze(frozen);

      frozen[1] = 'zhangxinxu';

      output.textContent += 'no log';
    })();
  } catch (error) {
    output.textContent = `${error.name}: ${error.message}`;
  }
});

reflect.addEventListener('click', () => {
  output.textContent = '';

  (function () {
    'use strict';

    var frozen = { 1: 81 };
    Object.freeze(frozen);

    var ok = Reflect.set(frozen, '1', 'zhangxinxu');

    output.textContent += `Reflect.set returned ${ok}\n`;
    output.textContent += 'no log';
  })();
});
Result:
Choose one strict-mode path.

5. Proxy Handlers Pair Naturally with Reflect

Code:
const input = document.querySelector('#proxyInput');
const output = document.querySelector('#proxyOutput');
const setButton = document.querySelector('#proxySet');
const readButton = document.querySelector('#proxyRead');
const clearButton = document.querySelector('#proxyClear');

const xyInput = new Proxy(input, {
  set(target, prop, value) {
    if (prop == 'value') {
      target.dispatchEvent(new CustomEvent('change'));
    }

    return Reflect.set(target, prop, value);
  },
  get(target, prop) {
    return Reflect.get(target, prop);
  }
});

input.addEventListener('change', () => {
  output.append('It changed~ ');
});

setButton.addEventListener('click', () => {
  xyInput.value = 'zhangxinxu';
});

readButton.addEventListener('click', () => {
  output.append(`value: ${xyInput.value} `);
});

clearButton.addEventListener('click', () => {
  input.value = '';
  output.textContent = '';
});
Result:
Proxy output is empty.

6. receiver Keeps Inherited Getters Honest

Code:
const output = document.querySelector('#receiverOutput');
const targetName = document.querySelector('#receiverTargetName');
const childName = document.querySelector('#receiverChildName');
const run = document.querySelector('#receiverRun');

run.addEventListener('click', () => {
  let miaoMiao = {
    _name: targetName.value || 'vaccine',
    get name() {
      return this._name;
    }
  };

  let noReceiverProxy = new Proxy(miaoMiao, {
    get(target, prop, receiver) {
      return target[prop];
    }
  });

  let reflectProxy = new Proxy(miaoMiao, {
    get(target, prop, receiver) {
      return Reflect.get(target, prop, receiver);
    }
  });

  let noReceiverChild = {
    __proto__: noReceiverProxy,
    _name: childName.value || 'Sinovac vaccine'
  };

  let reflectChild = {
    __proto__: reflectProxy,
    _name: childName.value || 'Sinovac vaccine'
  };

  output.textContent = [
    `target[prop] result: ${noReceiverChild.name}`,
    `Reflect.get(..., receiver) result: ${reflectChild.name}`
  ].join('\n');
});
Result:
Run the comparison.

7. Reflect Methods Mirror Existing APIs and Operators

Code:
const methods = [
  ['Reflect.apply(target, thisArgument, argumentsList)', 'Function.prototype.apply()'],
  ['Reflect.construct(target, argumentsList[, newTarget])', 'new target(...args)'],
  ['Reflect.defineProperty(target, prop, attributes)', 'Object.defineProperty()'],
  ['Reflect.deleteProperty(target, prop)', 'delete target[name]'],
  ['Reflect.get(target, prop[, receiver])', 'target[name]'],
  ['Reflect.getOwnPropertyDescriptor(target, prop)', 'Object.getOwnPropertyDescriptor()'],
  ['Reflect.getPrototypeOf(target)', 'Object.getPrototypeOf()'],
  ['Reflect.has(target, prop)', 'in operator'],
  ['Reflect.isExtensible(target)', 'Object.isExtensible()'],
  ['Reflect.ownKeys(target)', 'Object.keys()'],
  ['Reflect.preventExtensions(target)', 'Object.preventExtensions()'],
  ['Reflect.set(target, prop, value[, receiver])', 'target[prop] = value'],
  ['Reflect.setPrototypeOf(target, prototype)', 'Object.setPrototypeOf()']
];

const filter = document.querySelector('#tableFilter');
const body = document.querySelector('#tableBody');

function renderReflectTable() {
  const query = filter.value.toLowerCase();
  body.innerHTML = '';

  methods
    .filter(([reflect, similar]) => `${reflect} ${similar}`.toLowerCase().includes(query))
    .forEach(([reflect, similar]) => {
      const row = document.createElement('tr');
      const reflectCell = document.createElement('td');
      const similarCell = document.createElement('td');

      reflectCell.textContent = reflect;
      similarCell.textContent = similar;

      row.append(reflectCell, similarCell);
      body.append(row);
    });
}

filter.addEventListener('input', renderReflectTable);
renderReflectTable();
Result:
Reflect Method Similar To