官术网_书友最值得收藏!

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.

主站蜘蛛池模板: 恩施市| 彰武县| 甘孜县| 武清区| 敦煌市| 阿克苏市| 沧州市| 巫山县| 闽清县| 金沙县| 夏津县| 新乐市| 武夷山市| 合山市| 怀安县| 山东省| 扶风县| 闽清县| 工布江达县| 雷山县| 湾仔区| 穆棱市| 崇明县| 万宁市| 彝良县| 永靖县| 运城市| 土默特左旗| 精河县| 疏附县| 江达县| 芒康县| 富民县| 台北县| 大宁县| 海林市| 武冈市| 德安县| 霍林郭勒市| 永济市| 大荔县|