- Mastering JavaScript Design Patterns
- Simon Timms
- 933字
- 2021-08-05 17:14:57
Modules
Now that we have a complete class system, it would be good to address the global namespace discussed earlier. Again there is no first class support for namespaces but we can easily isolate functionality to the equivalent of a namespace. There are a number of different approaches to creating modules in JavaScript. We'll start with the simplest and add some functionality as we go along.
To start, we simply need to attach an object to the global namespace. This object will contain our root namespace. We'll name our namespace Westeros
; the code simply looks like this:
Westeros = {}
This object is, by default, attached to the top-level object, so we need not do anything more than that. A typical usage is to first check if the object already exists, and use that version instead of reassigning the variable. This allows you to spread your definitions over a number of files. In theory, you could define a single class in each file and then bring them all together as part of the build process, before delivering them to the client or using them in an application. The short form of this is:
Westeros = Westeros || {}
Once we have the object, it is simply a question of assigning our classes as properties of that object. If we continue to use the Castle
object, then it would look like this:
var Westeros = Westeros || {}; Westeros.Castle = function(name){this.name = name}; //constructor Westeros.Castle.prototype.Build = function(){console.log("Castle built: " + this.name)};
If we want to build a hierarchy of namespaces that is more than a single-level deep, that too is easily accomplished, as shown in the following code:
var Westeros = Westeros || {}; Westeros.Structures = Westeros.Structures || {}; Westeros.Structures.Castle = function(name){ this.name = name}; //constructor Westeros.Structures.Castle.prototype.Build = function(){console.log("Castle built: " + this.name)};
This class can be instantiated and used in much the same way as in previous examples:
var winterfell = new Westeros.Structures.Castle("Winterfell"); winterfell.Build();
Of course, with JavaScript, there is more than one way to build the same code structure. An easy way to structure the preceding code is to make use of the ability to create and immediately execute a function:
var Castle = (function () { function Castle(name) { this.name = name; } Castle.prototype.Build = function () { console.log("Castle built: " + this.name); }; return Castle; })(); Westros.Structures.Castle = Castle;
This code seems to be a bit longer than the previous code sample but I find it easier to follow due to its hierarchical nature. We can create a new Castle
class using the same structure as the previous one:
var winterfell = new Westeros.Structures.Castle("Winterfell"); winterfell.Build();
Inheritance using this structure is also relatively easily done. If we were to define a BaseStructure
class which was to be in the ancestor of all structures, then making use of it would look like this:
var BaseStructure = (function () { function BaseStructure() { } return BaseStructure; })(); Structures.BaseStructure = BaseStructure; var Castle = (function (_super) { __extends(Castle, _super); function Castle(name) { this.name = name; _super.call(this); } Castle.prototype.Build = function () { console.log("Castle built: " + this.name); }; return Castle; })(BaseStructure);
You'll note that the base structure is passed into the castle when the closure is evaluated. The highlighted line of code makes use of a helper method called __extends
. This method is responsible for copying the functions over from the base prototype to the derived class. This particular piece of code was generated from a TypeScript compiler which also, helpfully, generated an extends
method, which looks like this:
var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); };
We can continue the rather nifty closure syntax we've adopted for a class here to implement an entire module. This is shown in the following code:
var Westeros; (function (Westeros) { (function (Structures) { var Castle = (function () { function Castle(name) { this.name = name; } Castle.prototype.Build = function () { console.log("Castle built " + this.name); }; return Castle; })(); Structures.Castle = Castle; })(Westeros.Structures || (Westeros.Structures = {})); var Structures = Westeros.Structures; })(Westeros || (Westeros = {}));
Within this structure, you can see the same code for creating modules that we explored earlier. It is also relatively easy to define multiple classes inside a single module. This can be seen in the following code:
var Westeros; (function (Westeros) { (function (Structures) { var Castle = (function () { function Castle(name) { this.name = name; } Castle.prototype.Build = function () { console.log("Castle built: " + this.name); var w = new Wall(); }; return Castle; })(); Structures.Castle = Castle; var Wall = (function () { function Wall() { console.log("Wall constructed"); } return Wall; })(); Structures.Wall = Wall; })(Westeros.Structures || (Westeros.Structures = {})); var Structures = Westeros.Structures; })(Westeros || (Westeros = {}));
The highlighted code creates a second class inside of the module. It is also perfectly permissible to define one class in each file. Because the code checks to get the current value of Westeros before blindly reassigning it, we can safely split the module definition across multiple files.
The last few lines of highlighted code expose the class outside of the closure. If we want to make private classes that are only available within the module, then we need to exclude only that line. This is actually known as the revealing module pattern. We only "reveal" the classes that need to be globally available. It is good practice to keep as much functionality out of the global accessible namespace as possible.
- Boost.Asio C++ Network Programming(Second Edition)
- Learning Cython Programming(Second Edition)
- Java異步編程實戰
- Python for Secret Agents:Volume II
- Building a Home Security System with Raspberry Pi
- Developing Middleware in Java EE 8
- 正則表達式經典實例(第2版)
- Java EE 8 Application Development
- Flutter跨平臺開發入門與實戰
- 運用后端技術處理業務邏輯(藍橋杯軟件大賽培訓教材-Java方向)
- CoffeeScript Application Development Cookbook
- JavaScript應用開發實踐指南
- RocketMQ實戰與原理解析
- Python Linux系統管理與自動化運維
- INSTANT EaselJS Starter