Notes on Maintainable JavaScript

Part one covers coding style to make team code look as if written by a single person. Part two covers programming practices, with many valuable JavaScript programming lessons. Part three is about automation, but the toolchain it introduces feels quite outdated by the end of 2016.

Notes on Maintainable JavaScript

Part One

Basic Formatting

  1. It is recommended to add a blank line before each flow control statement (such as if and for statements).
  2. Variable names should be prefixed with nouns, while function names should be prefixed with verbs. Common verb conventions:
Verb Meaning
can Returns a boolean
has Returns a boolean
is Returns a boolean
get Returns a non-boolean value
set Used to save a value
  1. Constants should be written in uppercase letters with words separated by underscores.

  2. Scenarios for using null (think of it as an object placeholder):

    a. Initializing a variable that may later be assigned an object

    b. Comparing with an already initialized variable (which may or may not be an object)

    c. Passing as an argument when a function expects an object

    d. Returning as a value when a function’s return value is expected to be an object

  3. null == undefined // true

  4. typeof null === object // true

  5. Leave a blank line before comments, except at the beginning of a file.

  6. Code that is counterintuitive or intentionally unconventional should be commented.

  7. Leave a blank line after declarations.

  8. Primitive wrapper types: String, Boolean, Number — primitive values themselves do not have object characteristics.

Part Two

  1. Use a single global variable; mount all variables under one specific global variable.
  2. Create objects on the first level of the global object to serve as namespaces.
  3. Use function wrappers to create a zero-global-variable scenario:
1
2
3
4
(function(win) {
let doc = window.document;
// your code
}(window));
  1. Separate application logic — for example, encapsulate event handlers in a global object:
1
2
3
4
5
6
7
8
9
const MyApp = {
handleClick: e => {
this.showPopup(e);
},

showPopup: e => {
// event logic code
},
};
  1. Do not distribute the event object; only pass the required parameters:
1
2
3
4
5
6
7
8
9
const MyApp = {
handleClick: e => {
this.showPopup(e.clientX, e.clientY);
},

showPopup: (x, y) => {
// event logic code
},
};
  1. Make event handlers the only functions that touch the event object. Following points 4, 5, and 6 makes code easier to test:
1
2
3
4
5
6
7
8
9
10
11
12
const MyApp = {
handleClick: e => {
e.preventDefault();
e.stopPropagation();

this.showPopup(e.clientX, e.clientY);
},

showPopup: (x, y) => {
// event logic code
},
};
  1. When an object from frame A is passed into frame B, each frame effectively has its own copy, resulting in:
1
2
3
4
5
6
// true
frameAObjInstance instanceof frameAObj
//false
frameAObjInstance instanceof frameBObj

// The same applies to Function and Array, since each frame has its own constructors
  1. Use Array.isArray to check for arrays.
  2. To check whether an object has a property (avoid falsy property values — using if(obj['count']) is not recommended), use the in operator or the hasOwnProperty() method.
  3. Extract configuration data (hardcoded values).
  4. Throwing errors is like leaving yourself a sticky note explaining what went wrong.
  5. The only difference between the wrapper pattern and the adapter pattern is that the former creates a new interface while the latter implements an existing one.
  6. Avoid using feature inference and browser inference; use feature detection and user agent detection judiciously.
Author

LinYiBing

Posted on

2016-11-27

Updated on

2026-03-15

Licensed under