DEV Community

0 seconds of 1 hour, 13 minutes, 36 secondsVolume 90%
Press shift question mark to access a list of keyboard shortcuts
00:00
00:00
1:13:36
 
Caleb Weeks
Caleb Weeks

Posted on

4 2

Fun with JavaScipt proxies: observability, extensible chaining, and callable objects

I've been having a lot of fun playing with JavaScript proxies lately. It is fun to come up with creative ways of using them. In today's JavaScript meetup, we took a look at using proxies to handle obversability, create chainable APIs, and define callable objects.

The code for the proxies discussion can be found below and here

const helpers = require("./helpers");
const { log } = helpers;

// Proxies provide transparent obeservability
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const proxy = new Proxy(array, {});
log(array, proxy);
log(typeof array, typeof proxy);
log(
  Object.getOwnPropertyNames(array), 
  Object.getOwnPropertyNames(proxy)
);

//////// Observability ////////
const onUpdate = (obj) => (callback) => {
  return new Proxy(obj, {
    set: (_target, _prop, value) => {
      callback(value);
      Reflect.set(...arguments);
    },
  });
};

const person = onUpdate({
  firstName: "George",
  lastName: "Washington",
})(log);

person.lastName = "Clooney";

//////// Chaining outside functions ////////
const chain = (fns) => (obj) => {
  const isFunction = (fn) => typeof fn === "function";
  const chainify = (obj) => {
    if (typeof obj === "object" && obj !== null) {
      return new Proxy(obj, {
        get: (target, prop) => {
          switch (true) {
            case isFunction(target[prop]):
              return (...args) =>
                chainify(target[prop].apply(target, args));
            case isFunction(fns[prop]):
              return (...args) =>
                chainify(fns[prop].apply(target, [target, ...args]));
            default:
              return target[prop];
          }
        },
      });
    }
    return obj;
  };
  return chainify(obj);
};

chain(helpers)(array)
  .map((i) => i + 10)
  .log()
  .shuffle()
  .log()
  .zipWith(["a", "b", "c", "d", "e"], (a, b) => a + b)
  .log();

//////// Call object as a function ////////
const callable = (obj) =>
  new Proxy(() => {}, {
    apply(_target, _, [prop, ...args]) {
      return obj[prop] || obj._(prop);
    },
  });

const fib = callable({
  0: 1,
  1: 1,
  _: (n) => fib(n - 1) + fib(n - 2),
});

chain({ fib, log })(array)
  .map((i) => fib(i))
  .log();
Enter fullscreen mode Exit fullscreen mode

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (1)

Collapse
 
artydev profile image
artydev

Great thank you

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay