- Mastering TypeScript 3
- Nathan Rozentals
- 516字
- 2021-07-02 12:42:36
Encapsulation
One of the fundamental principles of object-oriented programming is encapsulation, the ability to define data, as well as a set of functions that can operate on that data, into a single component. Most programming languages have the concept of a class for this purpose—providing a way to define a template for data and related functions.
Let's first take a look at a simple TypeScript class definition:
class MyClass { add(x, y) { return x + y; } } var classInstance = new MyClass(); var result = classInstance.add(1,2); console.log(`add(1,2) returns ${result}`);
This code is pretty simple to read and understand. We have created a class, named MyClass, with a simple add function. To use this class, we simply create an instance of it, and call the add function with two arguments.
JavaScript, prior to ES6, does not have a class statement, but instead uses functions to reproduce the functionality of classes. Encapsulation through classes is accomplished by either using the prototype pattern, or by using the closure pattern. Understanding prototypes and the closure pattern, and using them correctly, is considered a fundamental skill when writing enterprise-scale JavaScript.
A closure is essentially a function that refers to independent variables. This means that variables defined within a closure function remember the environment in which they were created. This provides JavaScript with a way to define local variables, and provide encapsulation. Writing the MyClass definition in the preceding code, using a closure in JavaScript, would look something like this:
var MyClass = (function () { // the self-invoking function is the // environment that will be remembered // by the closure function MyClass() { // MyClass is the inner function, // the closure } MyClass.prototype.add = function (x, y) { return x + y; }; return MyClass; })(); var classInstance = new MyClass(); var result = classInstance.add(1, 2); console.log("add(1,2) returns " + result);
We start with a variable called MyClass, and assign it to a function that is executed immediately – note the })(); syntax near the bottom of the closure definition. This syntax is a common way to write JavaScript in order to avoid leaking variables into the global namespace. We then define a new function named MyClass, and return this new function to the outer calling function. We then use the prototype keyword to inject a new function into the MyClass definition. This function is named add and takes two parameters, returning their sum.
The last few lines of the previous code snippet show how to use this closure in JavaScript. Create an instance of the closure type, and then execute the add function. Running this code will log add(1,2) returns 3 to the console, as expected.
Looking at the JavaScript code versus the TypeScript code, we can easily see how simple the TypeScript looks compared to the equivalent JavaScript. Remember how we mentioned that JavaScript programmers can easily misplace a brace {, or a bracket ( ? Have a look at the last line in the closure definition: })(); Getting one of these brackets or braces wrong can take hours of debugging to find.