SidekickJS's blog

Productive advisory privacy pattern in Javascript

If you agree that privacy should be advisory, this is a useful pattern for achieving advisory privacy in Javascript while keeping your internal code neat.

Design goals

  1. Easy for internal code to use
  2. Obviously private when used in external code
  3. Allows redefinition of public functions
  4. Allows redefinitions of private functions

Pattern

The core idea is to export all private methods on a single object accessible on the main module.

var Module = {}
Module["-private"] = {
  privateOne: function() {},
  ...
}

This is a pain to reference internally, so we can store it on a local variable inside the module/closure:

var Module = {}
var p = Module["-private"] = {}

Now internal code can access private methods with via a single character:

p.somethingPrivate()

Advisory access

Exposing the private functions via the Module["-private"] property allows external code to access using an advisory syntax that makes the privacy very clear:

Module["-private"].somethingPrivate()

We’ve achieved 1 and 2, now we want to achieve 3 & 4: allowing redefinition of public and private functions.

Happy hacking

Since all uses of private functions internally go via the Module["-private"] object we can simply redefine them:

Module["-private"].somethingPrivate = function () {
  // new implementation
}

If this private method refers to other private methods we’ll want to keep it easy to access them. For instance: if we’re experimenting with changing a single line of a method in the REPL it’s a pain to have to rewrite all the internal p references into Module["-private"].

Since we’ve used a single variable for all library-internal access to private functions, it’s as simple as defining a local variable ‘p’ pointing to the private object in scope of our redefinition:

var p = Module["-private"];
Module["-private"].somethingPrivate = function () {
  // original code, which refers to 'p'
  p.blah(); p.x();
  // new code
  p.somethingElse()
}

Equally we can now redefine public methods in the same way, whether they refer to private methods or not. REPL experimentation abounds!

var p = vo["-private"];

Module.somethingPublic = function() {
  // original code, which refer to 'p'
  ourCrazyNewFeature();
}

Conclusion

This pattern is easy on library authors, and implements advisory privacy that allows users to access private methods for redefinition or REPL hacking.