📜 ⬆️ ⬇️

Creating JS Modules

Hello!

In this article I want to tell you about my approach to writing modules in JavaScript. Professionals are unlikely to find something new for themselves, but for beginners, I think, it will be useful to get acquainted with the proposed approach and the arguments in its favor.

The module from scratch


In my favorite IDE, when creating a new js-file, the following code is immediately inserted into the editor window:
(function (G, U){ "use strict"; var $ = G.jQuery, bool = "boolean", string = "string", number = "number", object = "object"; }(this, undefined)); 


Consider what exactly happens in these few lines.
')
1. Creating a private namespace.

First of all, a closed namespace is created by placing the code in a self-invoking anonymous function. In this case, two parameters G and U are passed to the anonymous function, which are assigned the values ​​of this and undefined respectively. Question: what in this case will be equal to this ? It depends on which platform you are working with, but in any case it will be a global namespace, such as in browsers, for example, the window object.

2. Use strict mode.

This line includes strict mode:
  "use strict"; 


I use strict mode for many reasons. Not only is its presence required for correct code validation using JSLint , it also blocks many unsafe constructs.
It would seem a completely innocent piece:

 for (i = 0; i < items.length; i += 1){ //-  } 


What could be the pitfalls here? Everything is simple: somewhere in the code before, the variable i has already been declared, and this cycle is nested:

 for (i = 0; i < myArr.length; i += 1){ // 50  ,  ,      for (i = 0; i < myArr.length; i += 1){ //-  } } 


Such a check will force you not only to define all variables before use, but also force you to check the loop arguments once more.

In addition, in strict mode, accessing an undeclared variable results in an execution error, while in normal mode the JavaScript interpreter will try to create this variable and assign it some value.

For example:

 alert(" : "+ error); 


If the error variable has not been previously declared, in normal mode, the user will be able to admire the message " : undefined" . In strict mode, this variable must be at least defined.

What if the target browser does not support strict mode? Nothing. Code written for strict mode will work in a loose mode without any problems, and the JavaScript interpreter will simply ignore the "use strict"; .

Private module variables


After the instruction "use strict"; , including a strict mode, there is a description of several variables. As you can see, I follow the “one var statement” pattern, which is also recommended for use. Agree, the construction described above does not look as bad as the one below:

 var $ = G.jQuery; var bool = "boolean"; var string = "string"; var number = "number"; var object = "object"; 


The variables bool , string , number and object further described below for more convenience:

 if (params.hasOwnProperty("title") && typeof params.title === string){ //-   result.title = params.title; } 


In addition, when using tools such as YUICompressor or Google Closure Compiler, the names of these variables will be reduced to one or two letters:

 if (p.hasOwnProperty("title") && typeof p.title === s){ r.title = p.title; } 


All variables declared here will be private and visible only within the module. If we need to create a generator function for unique id elements, this will be very simple:

 (function (G, U){ "use strict"; var id = 0, PREFIX = "my-library-id-prefix-"; function getNewId(){ id += 1; return PREFIX + id.toString(); } G.createId = getNewId; //  getNewId()       createId }(this, undefined)); 


But we can not send this function for export, but use it as a service inside the module:

 function Div(params){ //-    <div> var id = getId(); //id    ,      this.show = function(){ $("<div />", { "id": id }); } } 


Inclusion of the module in the library

Perhaps all of your modules will be designed as a single library, called, for example, JSui, and all functions should be called like this:

 var newDiv = new JSui.Div({ width: 200, height: 150 }); 


It would be possible to collect everything in one file, expanding a single object and exporting it to the global namespace, but debugging and editing several small modules is always easier than one big one. Therefore, we will use only one global variable and, if necessary, expand it with necessary properties. I do it like this:

File divs.js:

 (function(G, U){ "use strict"; var UI= G.JSui || {}; //  function Div(){ ... } UI.Div = Div; G.JSui = UI; }(this, undefined)); 


File labels.js:

 (function(G, U){ "use strict"; var UI= G.JSui || {}; //  function Label(){ ... } UI.Label = Label; G.JSui = UI; }(this, undefined)); 


Some will say that the assignment is G.JSui = UI; clearly too much. But do not make hasty conclusions! What if the specified module is connected first and the global JSui variable JSui not yet defined? The local UI variable will be assigned an empty object {} . Further, in the module code, we expand it, but export to the global namespace does not occur until the line is called:

  G.JSui = UI; 


If the global JSui object JSui already defined, the local UI variable receives a reference to it and expands it with new properties and methods. In this case, indeed, the above assignment will be redundant, however, one should not forget the simple fact that in this case the object will be passed by reference and performance will not be affected.

PS I did not touch on the topic of module dependency resolution, since This is a separate topic that deserves a whole article.

Source: https://habr.com/ru/post/231883/


All Articles