DEV Community

0 seconds of 0 secondsVolume 90%
Press shift question mark to access a list of keyboard shortcuts
00:00
00:00
00:00
 
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

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (1)

Collapse
 
artydev profile image
artydev

Great thank you

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more