JavaScript closures
Before we continue with this chapter, let's take a quick look at how TypeScript implements classes in the generated ES3 or ES5 JavaScript through a technique called closures. As we mentioned in Chapter 1, TypeScript – Tools and Framework Options, a closure is a function that refers to independent variables. These variables essentially remember the environment in which they were created. Consider the following JavaScript code:
function TestClosure(value) { this._value = value; function printValue() { console.log(this._value); } return printValue; } var myClosure = TestClosure(12); myClosure;
Here, we have a function named TestClosure that takes a single parameter, named value. The body of the function first assigns the value argument to an internal property named this._value, and then defines an inner function named printValue. The printValue function simply logs the value of this._value to the console. The interesting bit is the last line in the TestClosure function—we are returning the printValue function.
Now, take a look at the last two lines of the code snippet. We create a variable named myClosure and assign to it the result of calling the TestClosure function. Note that because we are returning the printValue function from inside the TestClosure function, this essentially also makes the myClosure variable a function. When we execute this function on the last line of the snippet, it will execute the inner printValue function, but remember the initial value of 12 that was used when creating the myClosure variable. The output of the last line of the code will log the value of 12 to the console.
This is the essential nature of closures. A closure is a special kind of JavaScript object that combines a function with the initial environment in which it was created. In our preceding sample, since we stored whatever was passed in through the value argument into a local variable named this._value, JavaScript remembers the environment in which the closure was created. In other words, whatever was assigned to the this._value property at the time of creation will be remembered, and can be reused later.
With this in mind, let's take a look at the JavaScript that is generated by the TypeScript compiler for the BaseClassWithConstructor class we were just working with:
var BaseClassWithConstructor = (function () { function BaseClassWithConstructor(_id) { this.id = _id; } return BaseClassWithConstructor; })();
Our closure starts with function () { on the first line, and ends with } on the last line. This closure first defines a function to be used as a constructor: BaseClassWithConstructor(_id).
This closure is surrounded by an opening bracket, (, on the first line, and a closing bracket, ), on the last line—defining what is known as a JavaScript function expression. This function expression is then immediately executed by the last two braces, ();. This technique of immediately executing a function is known as an Immediately Invoked Function Expression (IIFE). Our preceding IIFE is then assigned to a variable named BaseClassWithConstructor, making it a first-class JavaScript object, and one that can be created with the new keyword. This is how TypeScript implements classes in JavaScript.
The implementation of the underlying JavaScript code that TypeScript uses for class definitions is actually a well-known JavaScript pattern known as the module pattern. The good news is that an in-depth knowledge of closures, how to write them, and how to use the module pattern for defining classes will all be taken care of by the TypeScript compiler, allowing us to focus on object-oriented principles without having to write JavaScript closures using this sort of boilerplate code.