Skip to content

Instantly share code, notes, and snippets.

@WebReflection
Last active February 15, 2018 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WebReflection/a72fe03f43f7ce2aa8cdc9c17413f776 to your computer and use it in GitHub Desktop.
Save WebReflection/a72fe03f43f7ce2aa8cdc9c17413f776 to your computer and use it in GitHub Desktop.
Wrapping primitives keeping control of the exposed value and lazily defining every accessor

Two ways to do it, via Symbol

const Primitive = (() => {
  const secret = Symbol();
  const update = (obj, value) => {
    Object.defineProperty(obj, secret, {configurable: true, value});
  };

  function Primitive(value) {'use strict';
    update(this, value);
  }

  Primitive.prototype = new Proxy(
    Primitive.prototype,
    {
      get(target, property, receiver) {
        const value = receiver[secret][property];
        return Object.defineProperty(
          receiver,
          property,
          typeof value === 'function' ?
            {value() { return value.apply(receiver[secret], arguments); }} :
            {get() { return receiver[secret][property]; }}
        )[property];
      }
    }
  );

  return Primitive;

})();

or via WeakMap

const Primitive = (() => {
  const wm = new WeakMap;

  function Primitive(value) {'use strict';
    wm.set(this, value);
  }

  Primitive.prototype = new Proxy(
    Primitive.prototype,
    {
      get(target, property, receiver) {
        const value = wm.get(receiver)[property];
        return Object.defineProperty(
          receiver,
          property,
          typeof value === 'function' ?
            {value() { return value.apply(wm.get(receiver), arguments); }} :
            {get() { return wm.get(receiver)[property]; }}
        )[property];
      }
    }
  );

  return Primitive;

})();

The code could be tested as such:

// test
var s = new Primitive('abc');

s == 'abc';   // true
[...s]        // ["a", "b", "c"]
s.length;     // 3
s.toString(); //  "abc"

With the Symbol version it is possible, internally, to update the value via update(s, "def").

With WeakMap version, you can update via wm.set(s, "def");.

All string operations will work out of the box but you are free to silently change the value at distance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment