Thomas Nadin is a programmer

I'm an Undergraduate Software Engineer BSc at UCLan. You can follow me @nadinengland on Twitter or watch my commits on GitHub.

∀ x ∈ Visitors • Welcome( x )

Privy, Private Members for Objects in JavaScript

People who say you can't have private members in JavaScript are just plain wrong. JavaScript had private members right from the beginning in the form of functions. Variables defined in a function are only available in the scope of that function.

var Counter = function () {
    var value = 0;

    this.get = function () {
        return value;
    };

    this.add = function (other) {
        value += other;
    };
};

var counter = new Counter();
counter.value; // undefined, of course
counter.get(); // 0, encapsulation, hurrah!

These are called privileged methods as they have access to variables defined in the constructor. Like most things they come at a cost. For each object you create you must also create new functions for them, this could be wasteful.

N.B. Now before we continue, I am by no means saying this is wasteful or that under X circumstances with a blue moon and a cherry on top that my method is better than yours. This is mearly a demonstration that it is possible to securely access private members through prototype methods.

So lets begin.

As I've previously shown, privacy and encapsulation is done through function expressions in JavaScript. value was defined within the function as was only accessible through other functions due to closure.

Using closures we can create other interesting types of objects; one of which is a sealer. A sealer provides functionally takes an object and returns a means of getting it back. An example of one can be seen below.

var createSealer = function () {
    var value, key, sealer = {};

    // Seals `object` and returns one time key to retreive it
    sealer.seal = function (object) {
        value = object;
        return key = {};
    };

    // Returns the sealed object _once_ if `given` was used to seal it
    sealer.open = function (given) {
        var object = value;

        // Only give object if key is correct
        if (given === key) {
            // Empty the sealer
            value = undefined;

            return object;
        }
    };

    return sealer;
};

This sealer has two methods, seal which takes a object and returns a key, and open. seal which takes a key and returns an object if it was the correct key. This particular sealer enforces a one time key rule, meaning that when the object is retrieved through open it cannot be done so again.

Douglas Crockford did an excellent job of explaining sealers and unsealers in his Crockford on JavaScript series. I would definitely recommend you watch all the videos if you find this interesting.

What is useful about this is that we can give the respective methods to a pair of object and allow them to communicate over a untrusted channel.

var sealer = createSealer(),
    a = new A(sealer.seal, untrusted),
    b = new B(sealer.open, untrusted);
var A = function (seal, channel) {
    var key = seal("secret");
    channel.send(key);
};
var B = function (open, channel) {
    var key = channel.read();
    open(key); // "secret"
};

Why is this important? We can't trust the carrier channel, so we pass each object an opener or sealer that uses the key's identify to accessed the passed object.

There is no problem at all in the untrusted party having the key that because they lack the means to get at the important data, sealer.open.

Enter Privy

This is how Privy works. Each time you create an object constructor you must first wrap it in a Immediately-Invoked Function Expression (IIFE) creating the privacy need to communicate between objects and Privy.

In order to give each object it's own private object we assign it a function (defaultly given the property _) that closes over the constructor IIFE. The function's purpose is to seal the privates with a sealer; the same sealer of which we have the opener. When called, the function will simply return the key to open up the privates.

To see this in action let me define a class object constructor and prototype methods. This should be familiar to you if you have see a CoffeeScript class compiled to JavaScript.

var Person = (function () {
    // Here, the '_' isn't necessary as it is the default
    var p = Privy.create('_');

    function Person(name) {
        // Create the _ property on `this`
        // as a conviencce it also returns the privates
        var privates = p.initiate(this);

        // Set a private member
        privates.name = name;
    }

    Person.prototype.name = function () {
        var key = object._(),
            privates = p.sealer.open(key);

        return privates.name;
    };
}());

var thomas = new Person('Thomas');

thomas.name() // "Thomas"

What is unqiue about this code is that the privates are really private as well as being accessible through prototype methods. The caveat is that they can only be access within the IIFE, that is to say, anything in scope of p.

You will notice that the prototype method is doing the magic.

Person.prototype.name = function () {
    var key = object._(),
        privates = p.sealer.open(key);

    return privates.name;
};

The special function _ returns the key and p.sealer, which is available to all Person objects, contains the opener to retrieve the privates. This turns out to be something you need to do quite often if you want access to the privates. To trivialise this the Privy object p is actually a function that does this for you. As such, the name method can now be:

Person.prototype.name = function () {
    return p(this).name;
};

Now one thing to note is that p works on any Person object, and this works great for us in terms on Object Orientation. This means any person given reference to another person can see their privates (giggity); just like in other programming languages. So lets alter the class object constructor and prototype methods to see if two people are of the same age.

var Person = (function () {
    var p = Privy.create();

    function Person(name, age) {
        var privates = p.initiate(this);

        privates.name = name;
        privates.age = age;
    }

    // ...

    Person.prototype.sameAge = function (person) {
        return p(this).age === p(person).age;
    };
}());

var thomas = new Person('Thomas', 22),
    sarah  = new Person('Sarah', 22);

thomas.sameAge(sarah); // true

The benifit of having this is there only needs to be one set methods for each constructor and they can all facilitate their concerned objects. There is no need have privileged methods to get access to privates. But like everything, this comes at a cost. A function is added to every object you create to using this as well as one Privy object needed per class. It also takes 2 extra function calls to access the private object, one to seal, one to open.

Your millage may vary, but if you are creating a large number of objects that have some private data, this may save you in the long run. I have no scientific data to back that up however. Ultimately this was just a thought of mine that happened to turn into an actual GitHub repo which I am proud of.

If, Max & Min

Take a rather uninteresting function to clip off negative values:

int clip_zero(int value) {
    if (value < 0) return 0;

    return value;
}

Which could be used like so:

int account   = -1240;
int available = clip_zero(account);

This was something I had to do, as you might expect, to prevent division by zero. Something very trivial; yet I was writing an entire (albiet small) function for it. A weak but distinct code smell was in the air.

As it turns out, this can be avoided by using max. Which became extremely obvious once I thought about it for the first time.

int account   = -1240;
int available = max(account, 0);

Expanding on this, say you now want to keep the value within a particular range (appropriately substituting for MAX and MIN):

int account   = -1240;
int available = min(max(account, MAX), MIN);

Although the functions give the desired effect, when reading them they become obtrusive and difficult to read. Perhaps this is where it is better to write a short function:

// Clips the value at the given bounds
// No enforcement of `lower` <= `upper`
int clip(int value, int lower, int upper) {
    if (value > upper) return upper;
    if (value < lower) return lower;

    return value;
}

Back to our original example, this now can become:

int account   = -1240;
int available = clip(account, 0, 1000);

Much more short and concise allowing the statement's purpose to be self apparent.

The Switch Statement

I've never really got on with the switch statement. In my opinion, they are difficult to read and reak of procedural programming, goto:, label: and are way too verbose for my liking.

switch (reportType) {
  case kReportTypeDefect:
    [self showAlertWithTitle:@"Defect Reported"];
    break;
  case kReportTypeCloseCall:
    [self showAlertWithTitle:@"Close Call Reported"];
    break;
  default:
    [self showAlertWithTitle:@"Reported"];
    break;
}

My problem has always been, how do you extract which block of code is going to be executed. Improved readability could be gained by playing braces around the code:

switch (reportType) {
  case kReportTypeDefect: {
    [self showAlertWithTitle:@"Defect Reported"];
    break;
  }
  case kReportTypeCloseCall: {
  ...
}

Definately too much Christmas Tree Code for my liking.

A Different Angle

My problem with switch statements was not specifically with switch statements, but rather my use of them. I was using them to go down different code paths, making my code harder to follow and debug. By taking the action out of the switch statement it is now more straight forward, for me this is much easier to read:

NSString* title = nil;

switch (self.reportType) {
  case kReportTypeDefect: title = @"Defect Reported"; break;
  case kReportTypeCloseCall: title = @"Close Call Reported"; break;
  default: title = @"Reported" break;
}

[self showAlertWithTitle:title];

Maintainabily of the code has improved as it is much DRYer now, and as each case is only performing one action they comfortably fit on one line. I'm happy to use switch statements again.

Emails aren't forever

I signed into my oldest email account today, hotmail, to retrieve an email from many moons ago. When I signed in I was greeted with one email:

“Getting started with Hotmail”

All my emails are gone, from as far back as 2005, this is practically from when I was born on the internet.

Hotmail used to taunt me with things like this back when MSN was a thing, saying “You must sign in once ever 90 days or we will lock you account”. But that stopped a long time ago. Even worse I signed in earlier this year so this is bizarre.

Current Status: Getting ready to make copious backups of my Gmail account.

Common email (and domain) typos

A little while ago I got some inspiration from one of @jakemarsh's tweets, from it I went ahead and made email-typo-js.

The purpose of email-typo-js is to give you alternative Top Level Domains if it believes that what the user input was not valid. The most common use case for this is the classic .con TLD, clearly this should be .com. I have put together a simple live demo to give you a taste of the functionality, please note however that email-typo-js is just the logic to discover a typo, not to present it to the user.

Usage

Give EmailTypo.alternatives a string and it will return an array or alternatives or null if it had no luck.

// returns an %array% of alternatives, or %null%
EmailTypo.alternatives("email@email.con"); // => ['.com']

You would probably want to do some email validation before email-typo-js gets a look at the string.

EmailTypo.alternatives("email");        // => null
EmailTypo.alternatives("email.con");    // => ['.com']
EmailTypo.alternatives("@email.co.uj"); // => ['.uk']

// Validate first email = "email@email.con";
if (email.match(regExp) !== null && EmailTypo.alternatives(email) === null) {
  // We possibly have a valid email
}

Future Development

The next step is to get email-typo-js to recognise all the TLDs that are available to date, so that we know when a user has input something that simply doesn't exist.