An overview of information hiding in JavaScript

In general—meaning any programming language, client-side, server-side, non-web, mobile application, and almost anything else, perhaps even microcontrollers (which can now run a stripped-down Python)—there are different methodologies that generally have their own strengths and weaknesses. Steve McConnell's Code Complete: A Practical Handbook of Software Construction (http://tinyurl.com/reactjs-code-complete) discusses different methodologies and covers, for instance, how object-oriented programming's sweet spot is with larger projects than are really procedural programming's sweet spot. For most methodologies, his suggestion is that they have their strengths, weaknesses, and sweet spots, and under conditions X and Y, you should consider methodology Z. But there is one exception—information hiding. His simple advice on when to use information hiding is "As much as you can".

Procedural or structured programming is perhaps easy to overlook, and it's not pushing the envelope to use its strengths. But suppose we look at it when it first came out, with its functions/procedures, if-then-else, for/while loops, and procedure bodies not open to prying eyes. Now, if we compare this to straight assembler or machine code, with pre-Dijkstra-style use of gotos that do not even pretend to emulate structured control flow, then we understand that procedural or structured programming is really, really astounding. Also, it comes as a blinding flash of the obvious today because it has largely succeeded, to everyone's benefit. Flowcharts, which in the past were essential lifesavers for anybody hoping to understand a complex system, have become a novelty item. They appear on a mug, in an XKCD comic that shows how to deliver excellent tech support, or in other whimsical uses, as they are no longer needed to give any kind of road map to give some people—a sense of how to find their way through spaghetti.

Now a large system may be vastly more complex, and vastly larger than would fit into the memory or disk of an old, flowcharted, goto-navigated program, but procedural programming has effectively exorcized that ghost. Also, newer iterations in software engineering paradigms, such as object-oriented programming, have cut down the difficulty of understanding large systems. And in both cases, much of the benefit is a practical way to advance information hiding. With structured programming, you can navigate through source code without having to keep track of every point where the assembler or machine language renders a jump (that is, a goto). Both structured and object-oriented programming have historically allowed developers to unprecedentedly treat more of the program as a set of closed black boxes, and you only need to open and inspect a small fraction of them. They deliver information hiding.

An overview of information hiding in JavaScript

The preceding flowchart is a novelty flowchart from http://xkcd.com/627/. I've never seen a real flowchart for a program that someone and I were talking about.

A standard textbook example of information hiding, in classic Java, might be this:

class ObjectWithPrivateMember {
  private int counter;
  public ObjectWithPrivateMember() {
    counter = 0;
  }
  public void increment() {
    counter += 1;
  }
  public void decrement() {
    counter -= 1;
  }
  public void get_counter() {
    return counter;
  }
}

Uncharacteristic of a good example of live Java classes from production, this class has one private and four public members. The usual goal is to make the interesting heavy lifting as well hidden as possible and just present a simplified facade to the rest of the world. This is how Java's object-oriented programming delivers information hiding, and even though there are important differences between object-oriented languages and how they approach and handle objects, this is one of Java's strong suits. Not only are object methods supposed to be written procedurally—as black boxes that have defined inputs and outputs—but they are also encapsulated in objects, where multiple smaller black boxes can be subsumed under a larger black box. In this case, we see another benefit of information hiding: we are largely protected from the outside and free to make whatever internal changes we want without breaking outside usage, as long as we preserve the same behavior. Suppose we decide to keep a log of when the counter was changed and to what value. That's at least another private field and changes to the internals of the methods that represent the public interface, but we can make the changes without altering any single detail of any class that accesses this class. Now suppose we want even more logging and we want our log to record a full-stack trace. Internally, we need to use something such as Thread.currentThread.getStackTrace(), but externally, no one needs to know or care about our refactoring. In a larger class, we might find a bottleneck that can be improved considerably by switching to another equivalent algorithm. Because of the way Java's object-oriented programming delivers information hiding, we can make an awful lot of changes without disturbing other people, who can use our work without troubling themselves about anything other than our public interface.

Information hiding with JavaScript closures

We need to look a little further to see the patterns of information hiding. In Java, you are quickly taught the language features for information hiding, and encouraged with words such as the security maxim—"Stinginess with privileges is kindness in disguise"—to err on the side of declaring things non-public. In JavaScript, there may be future-reserved words such as public, private, and protected (which Douglas Crockford suggested may be there for Java programmers to feel more at home with JavaScript at the expense of understanding JavaScript's better side), but there are not the same kind of obvious mechanisms now. All of an object's members, whether they are functions are not, are open for inspection. JSON—another thing that spread like wildfire, but without people cursing its simplicity—has no mechanism offered to mark anything as non-public.

However, there is a technique to create private fields in a feature of some functional languages called a closure. It isn't exactly a technique that is simply present in the language to create information hiding, but it allows us to create objects with non-public information. To port the functionality of the preceding example, including the non-public state, we can have something shown as follows:

var factory_for_objects_with_private_member = function() {
  var counter = 0;
  return {
    'increment': function() {
      counter += 1;
    },
    'decrement': function() {
      counter -= 1;
    },
    'get_count': function() {
      return counter;
    }
  }
};

The example given here suggests how we might expand it. A more involved example could have more var functions storing fields and functions, and return a dictionary that would expose its public interface. But let's not simply jump for that; there are some interesting things along the way.

In a functional language, functions can contain other functions. Indeed, given JavaScript's syntax—where functions are first-class entities that can be stored in variables, passed as arguments, and so on—it would be surprising if functions could not be nested even two deep. So, the following syntax is legal:

var a = 1;
var inner = function() {
  var b = 2;
  return a + b;
}

But the same can legally be wrapped in a function, as follows:

var outer = function() {
  var a = 1;
  var inner = function() {
    var b = 2;
    return a + b;
  }
}

It is a basic feature of functional languages, including JavaScript's heritage, that inner functions can see variables from outer functions; hence both a and b are equally available to the inner function.

Now what happens if we change the outer function to return the inner function? Then we have the following:

var outer = function() {
  var a = 1;
  var inner = function() {
    var b = 2;
    return a + b;
  }
  return inner;
}
var result = outer();

By the time the function finishes executing, its variables have fallen out of scope. JavaScript now has var variables with the function scope and is in the process of getting let variables with the block scope, but any variables declared in either way in the outer function are no longer available. However, something interesting has happened; the inner function has survived the end of the outer function, but in a logically consistent fashion. The inner function should and does have access to its execution context. We have a closure.

This phenomenon can be used for information hiding, and information hiding is important. However, it may be argued that what is most interesting here is not that it can include non-public variables, potentially including functions, but that the execution context as a whole is maintained as long as something with access to it survives. This leaves an interesting territory to explore. A StackOverflow member once commented, "Objects are poor man's closures," and both objects and closures have interesting possibilities beyond the FAQ entry about how to use their features for information hiding. Even code complete, which may strongly endorse information hiding, never says, "Use information hiding as much as possible but nothing else."

Perhaps it would be harsh to blame functional language purists for saying, "JavaScript has to wait until it becomes 2 decades old before implementing tail call optimization, instead of punishing standard functional programming's use of recursion—as in, old enough to go from being a newborn infant to an adult under US laws." However, irrespective of anything else that may irk functional programmers about JavaScript, JavaScript did get closures right enough from the beginning, so much so that closures that retained the execution context were, and remain, a significant feature in JavaScript all the way along. And 2 decades later, they remain the primary, and possibly only, information hiding resource in most browsers.

Information hiding with JavaScript closures
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.105.227