JavaScript: The Definitive Guide, Sixth Editio javaScript权威指南(第6版) pdf 文字版-文字版, javascript电子书, 和javascript 有关的电子书:

9.9.2 Function Scope As a Private Namespace

9.9.2 Function Scope As a Private Namespace

Modules have a public API that they export: these are the functions, classes, properties, and methods that are intended to be used by other programmers. Often, however, module implementations require additional functions or methods that are not intended for use outside of the module. The Set._v2s()function of Example 9-6 is an example— we don’t want users of the Set class to ever call that function, so it would be better if it was inaccessible.

We can do that by defining our module (the Set class in this case) inside a function. As described in §8.5 , variables and functions defined within another function are local to that function and not visible outside of it. In effect, we can use the scope of a function (sometimes called a “module function”) as a private namespace for our module. Example 9-24 shows what this might look like for our Set class.

Example 9-24. A Set class in a module function

// Declare a global variable Set and assign it the return value of this function // The open parenthesis and the function name below hint that the function // will be invoked immediately after being defined, and that it is the function // return value, not the function itself, that is being assigned. // Note that this is a function expression, not a statement, so the name // "invocation" does not create a global variable. var Set = (function invocation() {

function Set() { // This constructor function is a local variable. this.values = {}; // The properties of this object hold the set this.n = 0; // How many values are in the set this.add.apply(this, arguments); // All arguments are values to add


// Now define instance methods on Set.prototype. // For brevity, code has been omitted here Set.prototype.contains = function(value) {

// Note that we call v2s(), not the heavily prefixed Set._v2s()

return this.values.hasOwnProperty(v2s(value)); }; Set.prototype.size = function() { return this.n; }; Set.prototype.add = function() { /* ... */ }; Set.prototype.remove = function() { /* ... */ }; Set.prototype.foreach = function(f, context) { /* ... */ };

// These are helper functions and variables used by the methods above // They're not part of the public API of the module, but they're hidden // within this function scope so we don't have to define them as a // property of Set or prefix them with underscores. function v2s(val) { /* ... */ } function objectId(o) { /* ... */ } var nextId = 1;

// The public API for this module is the Set() constructor function. // We need to export that function from this private namespace so that // it can be used on the outside. In this case, we export the constructor // by returning it. It becomes the value of the assignment expression // on the first line above. return Set;

}()); // Invoke the function immediately after defining it.

Note that this function definition followed by immediate invocation is idiomatic in JavaScript. Code that is to run in a private namespace is prefixed by “(function() {” and followed by “}());”. The open parenthesis at the start ensures that this is a function expression, not a function definition statement, so any function name that clarifies your code can be added to the prefix. In Example 9-24 we used the name “invocation” to emphasize that the function would be invoked immediately after being defined. The name “namespace” could also be used to emphasize that the function was serving as a namespace.

Once module code has been sealed up inside a function, it needs some way to export its public API so that it can be used from outside the module function. In Exam ple 9-24 , the module function returned the constructor, which we then assigned to a global variable. The fact that the value is returned makes it very clear that it is being exported outside of the function scope. Modules that have more than one item in their API can return a namespace object. For our sets module, we might write code that looks something like this:

// Create a single global variable to hold all collection-related modules var collections; if (!collections) collections = {};

// Now define the sets module

collections.sets = (function namespace() { // Define the various set classes here, using local variables and functions // ... Lots of code omitted...

// Now export our API by returning a namespace object

return { // Exported property name : local variable name AbstractSet: AbstractSet, NotSet: NotSet, AbstractEnumerableSet: AbstractEnumerableSet, SingletonSet: SingletonSet, AbstractWritableSet: AbstractWritableSet, ArraySet: ArraySet

}; }());

A similar technique is to treat the module function as a constructor, invoke it with new, and export values by assigning them to this:

var collections; if (!collections) collections = {}; collections.sets = (new function namespace() {

9.9 Modules | 249

// ... Lots of code omitted...

// Now export our API to the this object this.AbstractSet = AbstractSet; this.NotSet = NotSet; // And so on....

// Note no return value. }());

As an alternative, if a global namespace object has already been defined, the module function can simply set properties of that object directly, and not bother returning anything at all:

var collections; if (!collections) collections = {}; collections.sets = {}; (function namespace() {

// ... Lots of code omitted...

// Now export our public API to the namespace object created above collections.sets.AbstractSet = AbstractSet; collections.sets.NotSet = NotSet; // And so on...

// No return statement is needed since exports were done above. }());

Frameworks that define module loading systems may have other methods of exporting a module’s API. There may be a provides() function for modules to register their API, or an exports object into which modules must store their API. Until JavaScript has module management features of its own, you should choose the module creation and exporting system that works best with whatever framework or toolkit you use.

友情链接It题库(| 版权归yishouce.com所有| 友链等可联系|粤ICP备16001685号-1