Blog

JavaScript: Design Patterns 04 – Module Reveal Pattern

Module Reveal Pattern

Solves the following problems within the Module Pattern

  • Ensuring private members cannot interact with public ones
  • Reduce complexity introduced by the Module Pattern

Unlike the Module Pattern, the Module Reveal Pattern, does not place functions
and variables in the returned API object directly. Everything is created
within the private scope of the anonymous function.

Since both public and private members are within the same scope now, it is
important to differentiate between the two. This is commonly done by placing
an underscore in front of variable names that are private, to note them as such.
This of course requires that the developer be extra careful when using and
calling variables, making sure he is using the correct public or private one.

// IIFE will execute and return an object literal
var myLibrary = (function(){

// Private scope as everything within the anonymous function is hidden
// Private variables
let _privateData = 'this is private stuff';

// Private functions
function _doSomethingPrivate(){
console.log('Just did something private.')
}

// Public API functions
function doThis(){
console.log('This was done.');
}
function doThat(){
console.log('That was done.');
_doSomethingPrivate();
}

// The returned object contains the public API to the library
return {
doThis,
doThat
}

})();

// Accessible because they are on the API object
myLibrary.doThis();
myLibrary.doThat();

// NOT accessible because it is hidden within the scope of the anonymous function
// doSomethingPrivate(); // Uncommenting this line will throw an error

JavaScript: Design Patterns 03 – Module Pattern

Module Pattern

Solved the following problems in JavaScript

  • Creating access control to data that should be private
  • Providing a clear public API for custom libraries
  • True encapsulation that was not built into JavaScript to start with

Utilizing IIFEs to Control access

Immediately Invoked Functional Expression

// IIFE will execute and return an object literal
var myLibrary = (function(){

// Private scope as everything within the anonymous function is hidden
// Private variables
let privateData = 'this is private stuff';
// Private functions
function doSomethingPrivate(){
console.log('Just did something private.')
}

// The returned object contains the public API to the library
return {
doThis: function(){
console.log('This was done.');
},
doThat: function(){
console.log('That was done.');
/*
Accessible because this object was created within the scope of the
anonymous function that was executed by the IIFE.
*/
doSomethingPrivate();
}
}

})();

// Accessible because they are on the API object
myLibrary.doThis();
myLibrary.doThat();

// NOT accessible because it is hidden within the scope of the anonymous function
// doSomethingPrivate(); // Uncommenting this line will throw an error

JavaScript: Design Patterns 02 – Object Literal Pattern

Object Literal Pattern

The most basic approach to dealing with the pollution of the global scope
is to use a simple object literal to wrap a custom library.

Script One
var myLibrary = {
name: 'My super duper library',
say: function(){ return `This entire object will be shadowed...`; }
}
Script Two
var myLibrary = 'This is not even a library, it\'s a string. Boy are you hosed!';

NOTE: only applicable when using 'var' to create variables.
When using 'let', JavaScript will throw an error that the variable name has
already been taken. This includes the case where one of the variables was created
using 'var' and the other was created using 'let', JS will still throw an error.

Custom Name-Spaced Pattern

Uses object literal pattern

Although this may protect the variables, functions, and objects within your
custom library, there is still the issue that someone else may use the same
variable name for an object in their script as you used for the name of your
library's object wrapper.

To overcome this issue, it is standard practice to follow a common Java name-spacing
technique, use a registered domain name you own as your namespace.

Domain Namespace
// Build the domain structure using object literals
// checking to make sure those objects do not already exist
var com = com || {};
com.memorytin = com.memorytin || {};
com.memorytin.myLibrary = com.memorytin.myLibrary || {
name: 'My super duper library',
say: function(){ return `This entire object will be shadowed...`; }
};

Note: the above only works if you are using ‘var’ to create the initial
namespace object. If you use ‘let’, the browser will throw an error due to the
fact that you are using ‘com’ on the right side of the assignment operator and
it has not yet been instantiated.

JavaScript: Design Patterns 01 – Issues with Using the Global Scope

Shadowing

Due to the fact that all scripts are dumped into the JavaScript
global scope, all variables, function, and objects are placed
in that scope. As scripts are loaded into the global scope they are loaded in the
order they are located as the HTML is parsed, because 3rd party libraries are
often used, and because scripts are written by humans, there is a high likelihood
that one or more of those scripts will contain one or more items that have
the same name.

If one script loads and is followed by another that has items with identical
identifiers (names), those that exist in the previous script will be shadowed
or overwritten by those found in the following script. This leads to hard to
identify and correct bugs that can waste a lot of development resources.

Script One
// This script is loaded first
var varWithSameName = {
name: 'Tim',
say: function(){ return `This is the first variable with the name: ${this.name}`; }
}

console.log(varWithSameName.say());
// This script is loaded second
// overrides (shadows) the variable with the same name in the first file
var varWithSameName = {
name: 'Freddy',
say: function(){ return `This is the first variable with the name: ${this.name}`; }
}

console.log(varWithSameName.say());
Console Output
This is the first variable with the name: Tim
This is the first variable with the name: Freddy

NOTE: only applicable when using 'var' to create variables.
When using 'let', JavaScript will throw an error that the variable name has
already been taken. This includes the case where one of the variables was created
using 'var' and the other was created using 'let', JS will still throw an error.

Script One
// using 'let' when declaring variables corrects this problem
let willBreakIfShadowed = 'This will break if it is shadowed in another script.';
Script Two
// using 'let' when declaring variables corrects this problem
var willBreakIfShadowed = 'Broken since script one has this variable and used let to define it.';
Console Output
Uncaught SyntaxError: Identifier 'willBreakIfShadowed' has already been declared
at script-2.js:1

ElectronJS + Vue.js: Setting up ipcRenderer event handlers

When utilizing the ipcRenderer within a Vue.js view component, make sure you register the IPC event handler once for that component using ‘ipcRenderer.on’ in the ‘mounted’ lifecycle event of the Vue.js component.

If you make the mistake of placing the IPC event handler registration (ipcRenderer.on) inside a function that is called more than once within your component, you will notice a strange side-effect. What you will end up experiencing is that each time your function is called, the ipcRenderer will register a new event handler for the named event and each time that event is called you will see the handler executed X-number of times, with X equal to the number of times the function that contains ‘ipcRenderer.on’ has been called within your component.

If you are not careful, this is an easy mistake to make and a time consuming one to figure out.


 mounted: function () {
    this.$nextTick(function () {
        //Register IPC Renderer event handles once for this control
        ipcRenderer.on('name-of-your-event', (e, args) {
            // TODO: Hanlde the event broadcast here
        });
    });
}

Vue.js: Adding Keyboard Shortcuts to Components

A simple method for adding keyboard shortcuts to your components is to do the following:

    1. Add the ‘mounted’ lifecycle event hook to your component
    2. Add an event listener to the ‘window’ object and have it listen for the ‘keyup’ event
    3. Check for the proper keyboard key code and system modifier key (command/control, option/alt, shift, etc.) combination
    4. Execute custom logic in response

Example: here the key combination ‘alt+n’ is being checked for

 mounted: function () {
        this.$nextTick(function () {
            window.addEventListener('keyup', event => {
                if(event.altKey && event.keyCode === 78){
                    //TODO: do/call something here
                }
            })
        });
    }