[>_]in/$cat /posts/discard-after-usages.md
~/posts/discard-after-usages.md

Discard after usages

2022-01-25 · 411 words · 2 min read#javascript

Learn how to create self-discarding variables in JavaScript using closures, classes, proxies, and more. Explore practical implementations for managing variable usage limits effectively.

Have you ever noticed food labels warning you to discard the contents after a certain number of days? That made me wonder: how can we create a variable in JavaScript that automatically discards its content after X uses? Let's explore some implementations.

Encapsulate within a closure function

A closure is a simple and effective way to encapsulate state. By maintaining a usage counter within the closure, we can track the number of times a value is accessed.

javascript
function createPromoCode(validCode, maxUsages) {
  // Closure keeps state private, avoiding external modifications.
  let usageCounter = 0;
  return function() {
    if (usageCounter < maxUsages) { 
      usageCounter++;
      return validCode;
    }
    return null;
  };
}

const promo = createPromoCode('free beer 🍻😆', 3);
console.log(`You are getting a ${promo()}`);
console.log(`You are getting a ${promo()}`);
console.log(`You are getting a ${promo()}`);
console.log(`You are getting a ${promo()}`);

Place inside a Getter/Setter

JavaScript ES5 has getter and setter syntax, which fits very well as a solution.

javascript
Object.defineProperty(window, 'discardAfterUsed', {
  get() {
    if (this.read) {
      return null;
    }

    this.read = true;
    return this.value;
  },
  set(value) {
    this.read = false;
    this.value = value;
  },
});

window.discardAfterUsed = 'one-time free beer'
console.log(`You are getting a ${discardAfterUsed}`);
console.log(`You are getting a ${discardAfterUsed}`);

While defining a property on the window object is quick for demonstration purposes, it's not a practical solution.

Implement a class

A more structured approach involves creating a class, making it reusable and clear.

javascript
class DiscardAfterUsed {
  constructor(value) {
    this._value = value;
  }

  get value() {
    if (this._value !== null && this._value !== undefined) {
      const temp = this._value;
      this._value = null; // Ready for garbage collector
      return temp;
    }
    return null;
  }
}

const onceOnly = new DiscardAfterUsed('one-time free beer');

console.log(`You are getting a ${onceOnly.value}`);
console.log(`You are getting a ${onceOnly.value}`);

Use proxy

Using a proxy is often more complex than other solutions, but it is flexible and does not modify the original value.

javascript
const discardAfterUsedHandler = {
  get: function(target, prop, receiver) {
    if (prop !== 'code') {
      return Reflect.get(target, prop, receiver);
    }

    if (!receiver.read) {
      receiver.read = true;
      return target[prop];
    }
    return null; 
  }
};

const promo = { code: 'one-time free beer' };
const proxiedObj = new Proxy(promo, discardAfterUsedHandler);
console.log(`You are getting a ${proxiedObj.code}`);
console.log(`You are getting a ${proxiedObj.code}`);

In conclusion, if you need a straightforward solution, closures work well. For a more reusable and structured approach, a class is ideal. When handling multiple properties dynamically, proxies offer the most flexibility.

[>_] in $

type a command and press enter, or press ⌘K for suggestions

Run a command

Help

how this site works · esc to close

About this site

This is Trinh Nguyen's dev blog, dressed up as a terminal. Instead of clicking through pages, you run commands against a small virtual file system with three directories:

~/posts~/topics~/about

How to use it

  • Type a command at the prompt and press enter. Output is added below, like a shell session.
  • Press ⌘K (Ctrl+K on Windows/Linux) to open the command palette with suggestions and your recent commands.
  • The /posts, /topics and /about links in the header are shortcuts for cd ~/posts && ls and friends.
  • Chain commands with &&, e.g. cd ~/about && cat me.md.
  • To read an article, ls a directory, then cat the file you want.

Commands