What is the use of Proxy and Reflect in JavaScript?
Rajesh Royal

Rajesh Royal @rajeshroyal

About: Designer, Front-end Developer, Traveller, Hooper. I design and code beautifully simple things, and I love what I do.

Location:
India
Joined:
Mar 27, 2020

What is the use of Proxy and Reflect in JavaScript?

Publish Date: May 26 '22
33 18

I have read the documentation for Proxy and Reflect on MDN but didn't understand much. Can anyone please explain or mention the real world use of these ES6 features.

  • One of the good use of proxy I found is that we can declare our object values as private -
const object = {
    name: "Rajesh Royal",
    Age: 23,
    _Sex: "Male"
}

const logger = {
    get(target, property){
        if(property.startsWith("_")){
            throw new Error(`${property} is a private property.`);
        }

        console.log(`Reading the property ${property}`);
        return target[property];
    }
}

const Logger = new Proxy(object, logger);

// now if you try to access the private property it will throw an error
Logger._Sex

Uncaught Error: _Sex is a private property.
    at Object.get (<anonymous>:4:19)
    at <anonymous>:1:8
Enter fullscreen mode Exit fullscreen mode

Comments 18 total

  • ninja in pajama
    ninja in pajamaMay 26, 2022

    well, hard to imagine a use case for that unless you're building your own framework or a library. If someone asks me such stuff in an interview, I would go 'cmon are you doing some rocket science'?)

    • Rajesh Royal
      Rajesh RoyalMay 26, 2022

      🙃🙃

    • Ivan Jeremic
      Ivan JeremicMay 26, 2022

      Right, I for example use proxies for reactivity in the front-end framework I build.

    • codingjlu
      codingjluMay 27, 2022

      But there's this point I force myself to learn anything and everything about JavaScript just to convince myself I'm good at it :/.

  • ninja in pajama
    ninja in pajamaMay 26, 2022

    You may find this helpfull - use-es6-proxies-to-enhance-your-ob...

  • Rodrigo Nascimento
    Rodrigo NascimentoMay 26, 2022

    Once I used Reflect on a jest test to simulate the class/ method spyOn

    • Rajesh Royal
      Rajesh RoyalMay 26, 2022

      Can you please share code snippet if possible.

      • Rodrigo Nascimento
        Rodrigo NascimentoMay 26, 2022
        repositoryClass = module.get<IRepo>(repo);
        const queryBuilder = jest.fn().mockReturnValue({
            getMany: jest.fn().mockReturnValue({ ...object }),
        });
        Reflect.set(
            repositoryClass,
            'queryBuilderMethod',
            queryBuilder
        );
        
        Enter fullscreen mode Exit fullscreen mode

        I was using typeorm + nestjs + jest so it has a queryBuilder and I wanted that my custom queryBuilderMethod "inherits" some default queryBuilder methods, because in that case, I was using the default plus the custom.
        So my other custom methods that depends on those configuration custom + default will have the right params and return the query as intended

  • Jan Küster 🔥
    Jan Küster 🔥May 26, 2022

    I wrote a tiny package that uses proxy to create factories for any of your existing es6 (or old es5) classes and allows to define private fields or function based on a rule function: github.com/jankapunkt/js-class-pri...

    No need to fully rewrite the classes to support private members (plus I still dislike the choice of the hash character for the private fields feature)

  • Gaurav Saini
    Gaurav SainiMay 26, 2022

    I’m not too familiar with Reflect, but have a pretty good analogy for proxies that I’m sure will be helpful
    If you know about Express and how the whole middleware pattern works, then proxies are exactly like middleware but for plain JavaScript objects. So, whenever you read from and object or make any changes to an object you can execute custom behaviour on those operations.
    And as for the use cases, the only real ones I can think of is when you’re building some framework.

  • peerreynders
    peerreyndersMay 26, 2022

    First time I came across Reflect was in the web components native shim:

      const wrapperForTheName = {
        'HTMLElement': function HTMLElement(this: HTMLElement) {
          return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
        },
      };
      window.HTMLElement = (wrapperForTheName[
        'HTMLElement'
      ] as unknown) as typeof HTMLElement;
      HTMLElement.prototype = BuiltInHTMLElement.prototype;
      HTMLElement.prototype.constructor = HTMLElement;
      Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
    
    Enter fullscreen mode Exit fullscreen mode

    MDN: Reflect.construct().

    Browsers implement custom elements as native classes (separate from JS classes).

    Some tooling insists on compiling down to ES5 and using Reflect.construct() instead of new makes it possible to use custom elements from ES5 code (obviously the browser has to support custom elements which implies that it also supports classes (ES2015)).


  • Conan
    ConanMay 26, 2022

    I posted this elsewhere, but here's an example use-case:

    Let's say you want to use arrays as accessors, like this:

    const array = "the five boxing wizards jump quickly".split(" ");
    const words = fancy(array);
    
    words[[3, -1, -2]];
    // ["wizards", "quickly", "jump"]
    
    words[-1] = "swiftly";
    // ["the", "five", "boxing", "wizards", "jump", "swiftly"]
    
    words[[0, -1]] = ["alpha", "omega"];
    // ["alpha", "five", "boxing", "wizards", "jump", "omega"]
    
    Enter fullscreen mode Exit fullscreen mode

    You can use Proxy and Reflect to achieve it:

    const parseIndexesString = (indexes, maxIndex) =>
      indexes
        .split(",")
        .map((x) => x.trim())
        .map((x) => (/^-\d+$/.test(x) ? maxIndex + +x : x));
    
    const fancyArrayAccessors = {
      get(obj, prop) {
        if (/^\d+$/.test(prop)) {
          return Reflect.get(...arguments);
        }
        const props = parseIndexesString(prop, obj.length);
        return props.map((prop) => obj[prop]);
      },
      set(obj, prop, value) {
        if (/^\d+$/.test(prop)) {
          return Reflect.get(...arguments);
        }
        const props = parseIndexesString(prop, obj.length);
        return props.map((prop, idx) => 
          (obj[prop] = Array.isArray(value) ? value[idx] : value)
        );
      }
    };
    
    const fancy = (arr) => new Proxy(arr, fancyArrayAccessors);
    
    Enter fullscreen mode Exit fullscreen mode

    Here, Reflect is being used to take care of the "default" case of accessing an array using a normal numerical index.

    The rest of the time we're abusing the fact that any key in arr[key] form gets coerced into a string, so can be parsed into whatever we like once it reaches the getter/setter in a Proxy handler.

  • Rajesh Royal
    Rajesh RoyalMay 27, 2022

    man these are really very helpful 🤘 thanks

Add comment