Kyle Edwards

Fun With Proxies

You can do some nifty tricks with JS proxies to add behavior to plain objects. Below are some examples to create object literals whose properties expire. Prank your coworkers! Make your code less readable!

With Expiry

const expiryCache = (ms) => {
  return new Proxy({}, {
    get: function (target, property) {
      if (target[property] && Date.now() < target[property].expires) {
		return target[property].value;
      }
      return undefined;
    },
    set: function (target, property, value) {
      target[property] = {
        value,
        expires: Date.now() + ms,
      }
    }
  });
};

LRU Cache

const lruCache = (n) => {
  let head = null;
  let tail = null;
  let size = 0;
  return new Proxy({}, {
    get: function (target, property) {
      if (target[property]) {
        if (target[property].prev) {
          target[property].prev.next = target[property].next;
        }
        if (target[property].next) {
          target[property].next.prev = target[property].prev;
        }
        if (tail) {
          tail.next = target[property];
        }
        if (target[property] === head && size > 1) {
          head = head.next;
        }
        tail = target[property];
        return tail.value;
      }
      return undefined;
    },
    set: function (target, property, value) {
      if (target[property]) {
        if (target[property].prev) {
          target[property].prev.next = target[property].next;
        }
        if (target[property].next) {
          target[property].next.prev = target[property].prev;
        }
      } else {
        size++;
      }
      target[property] = {
        property,
        value,
        next: null,
        prev: tail,
      };
      if (tail) {
        tail.next = target[property];
      }
      tail = target[property];
      if (size > n) {
        size = n;
        if (head) {
          const propToDelete = head.property;
          head = head.next;
          delete target[propToDelete];
        }
      }
      if (!head) {
        head = target[property];
      }
      if (target[property] === head && size > 1) {
        head = head.next;
      }
    }
  });
};

Inspired by: https://twitter.com/kognise7/status/1631502923044716546