Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Async Scripts and Namespacing

Spread the love

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at some basic coding and design patterns.

Async JavaScript Loading

By default, script tags are loading synchronously.

This means they’re loading in the order that they’re added in the code.

Therefore, we can move our script tags to the bottom of the page so that we see the HTML content first.

HTML5 has the defer attribute to let us load scripts asynchronously but in the order that they’re added in.

For instance, we can write:

<script defer src="script.js"></script>

We just add the defer attribute to the bottom of the script.

This isn’t supported by older browsers, but we can do the same thing by loading our scripts with JavaScript.

For instance, we can write:

<script>
  (function() {
    const s = document.createElement('script');
    s.src = 'script.js';
    document.getElementsByTagName('head')[0].appendChild(s);
  }());

</script>

We create a script element, set the src value to the script path and attach it as a child of the head tag.

Namespaces

We can add an object to namespace our app.

This way, we won’t have so many global variables in our app.

For instance, we can write:

let APP = APP || {};

to create a MYAPP namespace.

Then we can add properties to it by writing:

APP.event = {};

And then we can add properties to the event property:

APP.event = {
  addListener(el, type, fn) {
    // ..
  },
  removeListener(el, type, fn) {
    // ...
  },
  getEvent(e) {
    // ...
  }
  // ...
};

Namespaced Constructors

We can put constructors inside our namespace object.

For instance, we can write:

APP.dom = {};
APP.dom.Element = function(type, properties) {
  const tmp = document.createElement(type);
  //...
  return tmp;
};

We have the Element constructor to create some object with.

A namespace() Method

We can create a namespace method to let us create our namespace dynamically.

For instance, we can write:

APP.namespace = (name) => {
  const parts = name.split('.');
  let current = APP;
  for (const part of parts) {
    if (!current[part]) {
      current[part] = {};
    }
    current = current[part];
  }
};

We create a namespace method that takes a string with words separated by dots.

Then we add the properties to the current object by looping through them.

Once we defined it, we can use it by writing:

APP.namespace('foo.bar.baz');

console.log(APP);

We see the foo.bar.baz property in the console log.

Init-Time Branching

Different browsers may have different functions that implement the same functionality.

We can check for them and add the functionality we want by checking and which one exists and then add the one that exists to our namespace object.

For instance, we can write:

let APP = {};

if (window.addEventListener) {
  APP.event.addListener = function(el, type, fn) {
    el.addEventListener(type, fn, false);
  };
  APP.event.removeListener = function(el, type, fn) {
    el.removeEventListener(type, fn, false);
  };
} else if (document.attachEvent) {
  APP.event.addListener = function(el, type, fn) {
    el.attachEvent(`on${type}`, fn);
  };
  APP.event.removeListener = function(el, type, fn) {
    el.detachEvent(`on${type}`, fn);
  };
} else {
  APP.event.addListener = function(el, type, fn) {
    el[`on${type}`] = fn;
  };
  APP.event.removeListener = function(el, type) {
    el[`on${type}`] = null;
  };
}

We check for different versions of the addEventListener and removeEventListener and their equivalents and put them one that exists in our namespace.

This puts all the feature detection code in one place so we don’t have to that multiple times.

Conclusion

We can create namespace objects to keep our code away from the global namespace.

JavaScript scripts can be loaded asynchronously.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *