Le chargement et l'exécution du module sont emballés dans Node.js afin que les variables du fichier du module soient fermées et ne polluent pas les variables globales ni n'entrent en conflit avec d'autres.
Pour les modules front-end, nos développeurs placent généralement le code du module dans une fermeture pour éviter les conflits avec les autres.
Comment encapsuler les modules communs à Node.js et au front-end, on peut se référer à l'implémentation d'Underscore.js, qui est un module de fonction fonctionnel commun à Node.js et au front-end, voir le 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._ = _; }
Déterminez d'attribuer la variable locale _ aux exportations en jugeant si les exportations existent, rétrocompatible avec l'ancienne API require(), si dans le navigateur, transmettez un identifiant de chaîne "_" comme objet global ; fermeture complète Comme suit :
(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);
Une fermeture est construite via la définition de fonction call(this) appelle la fonction sous cet objet pour éviter que les variables internes ne contaminent la portée globale. Dans le navigateur, cela pointe vers l'objet global (objet fenêtre) et la variable "_" est affectée à l'objet global "root._" pour les appels externes.
Lo-Dash, qui est similaire à Underscore.js, utilise également une solution similaire, mais est compatible avec le chargement de modules AMD :
;(function() { /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; /** Used to determine if values are of the language type Object */ var objectTypes = { 'boolean': false, 'function': true, 'object': true, 'number': false, 'string': false, 'undefined': false }; /** Used as a reference to the global object */ var root = (objectTypes[typeof window] && window) || this; /** Detect free variable `exports` */ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; /** Detect free variable `module` */ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; /** Detect the popular CommonJS extension `module.exports` */ 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));
Jetons un coup d'œil au code principal de la fermeture d'encapsulation de Moment.js :
(function (undefined) { var moment; // check for nodeJS var hasModule = (typeof module !== 'undefined' && module.exports); /************************************ Exposing Moment ************************************/ function makeGlobal(deprecate) { var warned = false, local_moment = moment; /*global ender:false */ 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);
Comme le montrent les exemples ci-dessus, lors de l'encapsulation de modules communs à Node.js et au front-end, la logique suivante peut être utilisé :
if (typeof exports !== "undefined") { exports.** = **; } else { this.** = **; }
C'est-à-dire que si l'objet exports existe, les variables locales sont chargées sur l'objet exports, et si elles n'existent pas, elles sont chargées sur l'objet global. Si vous ajoutez la compatibilité de la spécification ADM, ajoutez un jugement supplémentaire :
if (typeof define === "function" && define.amd){}
Pour plus d'articles liés à la méthode d'encapsulation des modules généraux dans Node.js, veuillez faire attention au site Web PHP chinois !