DEV Community

Budy
Budy

Posted on • Updated on

How I Structure My JavaScript Code

Structuring JavaScript codes properly is very important to make our code clean, easy to understand and to maintain. If you work in a team, you also need to have a "de facto" format that everyone should follow.

Javascript Image

When building a web application I usually use these Structure.

Working with VanillaJS

!(function(window, document, M, undefined) {
  'use strict';

   // local vars...

   const session = {};
   const PI = 3.14;

   // local functions...

   function render() {
     // ...
   }

   // elems...

   const btnSave = document.getElementById('save');
   const btnCancel = document.getElementById('cancel');

   // events listener...

   btnSave.addEventListener('click', function() {
     //...
   });


   btnCancel.addEventListener('click', function() {
     //...
   });


})(this, document, MyLib);

Working With jQuery

!(function(window, document, $, undefined) {
  'use strict';

   // local vars...

   const session = {};
   const PI = 3.14;

   // local functions...or use Class

   function render() {
     return $.ajax({
        url: SITE_URL + 'form/fetch',
        data: {
          page: page, search: search
        },
        method: 'GET'
      });
   }


   // events listener...

   $("#btnSave").click(function() {
     //...
     render().done(response => {
       console.log(response);
     }).fail((x, h, r) => {
       console.log('Error' + r);
     });
   });


   $("#btnCancel").click(function() {
     //...
   });


})(this, document, jQuery);

With ES6 Class

!(function(window, document, M, undefined) {
  'use strict';

   // Class...

   /**
    * CLass Environment
    */
   class CL_Environment {
    constructor() {}

    /**
     * Get data environment
     * @param {object} filter
     * @param {number} page
     * @param {callback} next 
     * @return {Promise} Object
     */
    async getEnvironment(filter = {}, page = 1, next) {
      try {
        let params = Utils.buildQueryParam(Object.assign(filter, {
          page: page
        }));
        const environment = await fetch(SITE_URL + 'environment/fetch' + params, {
          method: 'GET',
          headers: {
            'X-Requested-With': 'XmlHttpRequest'
          }
        });
        const result = await environment.json();
        return next(result);
      } catch (error) {
        console.error(error);
        return next(false);
      }
    }

   }



   // local vars...
   const Environment = new CL_Enviroment();
   const session = {};
   const PI = 3.14;

   // local functions...

   function render() {
     // ...
   }

   // elems...

   const btnSave = document.getElementById('save');
   const btnCancel = document.getElementById('cancel');

   // events listener...

   btnSave.addEventListener('click', function() {
     Environment.getEnvironment({}, 1, result => {
       // ..
     });
     //...
   });


   btnCancel.addEventListener('click', function() {
     //...
   });


})(this, document, MyLib);

If you see the examples above, all are wrapped inside IIFE (Immediately Invoked Function Expression), Its a good practice because all codes inside the IIFE is private and inaccessible from outside so it wont be polluting the global namespace, also You don't have to worry about your friends code overriding yours.

If you are creating libraries, You may use the common design pattern like UMD (Universal Module Definition) or simply a Revealing Module Pattern.

Top comments (0)