The encapsulation method of a generic module in node. js

  • 2020-03-30 03:13:03
  • OfStack

In node. js, the module load and execution are wrapped so that the variables in the module file are in a closure and do not pollute the global variables and conflict with others.

Front-end modules are often placed in a closure by us developers to avoid conflict with others.

How to encapsulate node. js and front-end common module, we can refer to Underscore. Js implementation, it is a node. js and front-end common function module, see the code:

 
// Create a safe reference to the Underscore object for use below.
  var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

  // Export the Underscore object for **Node.js**, with
  // backwards-compatibility for the old `require()` API. If we're in
  // the browser, add `_` as a global object via a string identifier,
  // for Closure Compiler "advanced" mode.
  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    root._ = _;
  }

To assign a local variable _ to exports by determining whether exports exists, backwards compatible with the old require() API, and if in a browser, through a string identifier "_" as a global object. The complete closure is as follows:

(function() {

  // Baseline setup
  // --------------

  // Establish the root object, `window` in the browser, or `exports` on the server.
  var root = this;

  // Create a safe reference to the Underscore object for use below.
  var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

  // Export the Underscore object for **Node.js**, with
  // backwards-compatibility for the old `require()` API. If we're in
  // the browser, add `_` as a global object via a string identifier,
  // for Closure Compiler "advanced" mode.
  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    root._ = _;
  }
}).call(this);


A closure is built from the function definition. Call (this) calls the function in this object to avoid the corruption of internal variables into the global scope. In the browser, this points to the global object (the window object) and assigns the "_" variable to "root._" on the global object for external invocation.

Underscore. Js and similar Lo-Dash, is also used a similar scheme, only compatible with AMD module load compatibility:

 
;(function() {

  
  var undefined;
    
      var objectTypes = {
        'boolean': false,
        'function': true,
        'object': true,
        'number': false,
        'string': false,
        'undefined': false
      };
  
  var root = (objectTypes[typeof window] && window) || this;

  
  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;

  
  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;

  
  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;



  // expose Lo-Dash
  var _ = runInContext();

  // some AMD build optimizers, like r.js, check for condition patterns like the following:
  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
    // Expose Lo-Dash to the global object even when an AMD loader is present in
    // case Lo-Dash was injected by a third-party script and not intended to be
    // loaded as a module. The global assignment can be reverted in the Lo-Dash
    // module by its `noConflict()` method.
    root._ = _;

    // define as an anonymous module so, through path mapping, it can be
    // referenced as the "underscore" module
    define(function() {
      return _;
    });
  }
  // check for `exports` after `define` in case a build optimizer adds an `exports` object
  else if (freeExports && freeModule) {
    // in Node.js or RingoJS
    if (moduleExports) {
      (freeModule.exports = _)._ = _;
    }
    // in Narwhal or Rhino -require
    else {
      freeExports._ = _;
    }
  }
  else {
    // in a browser or Rhino
    root._ = _;
  }
}.call(this));

Now let's look at the main code for the encapsulated closure of moment.js:
 
(function (undefined) {
    var moment ; 
    // check for nodeJS
    var hasModule = (typeof module !== 'undefined' && module.exports) ; 


    function makeGlobal(deprecate) {
        var warned = false, local_moment = moment;
        
        if (typeof ender !== 'undefined') {
            return;
        }
        // here, `this` means `window` in the browser, or `global` on the server
        // add `moment` as a global object via a string identifier,
        // for Closure Compiler "advanced" mode
        if (deprecate) {
            this.moment = function () {
                if (!warned && console && console.warn) {
                    warned = true;
                    console.warn(
                            "Accessing Moment through the global scope is " +
                            "deprecated, and will be removed in an upcoming " +
                            "release.");
                }
                return local_moment.apply(null, arguments);
            };
        } else {
            this['moment'] = moment;
        }
    }

    // CommonJS module is defined
    if (hasModule) {
        module.exports = moment;
        makeGlobal(true);
    } else if (typeof define === "function" && define.amd) {
        define("moment", function (require, exports, module) {
            if (module.config().noGlobal !== true) {
                // If user provided noGlobal, he is aware of global
                makeGlobal(module.config().noGlobal === undefined);
            }

            return moment;
        });
    } else {
        makeGlobal();
    }
}).call(this);

As you can see from the examples above, the following logic can be used to encapsulate node. js and front-end generic modules:
 
if (typeof exports !== "undefined") {
    exports.** = **;
} else {
    this.** = **;
}

That is, local variables are loaded on the exports object if it exists and on the global object if it does not. Add to this the compatibility of the ADM specification, then add a judgment:
if (typeof define === "function" && define.amd){}


Related articles: