Motionstrand Docs

Motionstrand Docs

  • Docs

›Coding

Coding

  • JavaScript
  • CSS
  • PHP
  • Twig

Tools

  • Git
  • NPM/Package JSON
  • Gulp

Platform

  • Acquia Resources
  • Pantheon Resources
  • SSL/Domain Process
  • Change Management SOP
  • Cross Agency Web Development Roles and Responsibilities
  • Web Application Setup and Maintenance RACI

JS Coding Standards

Javascript

Early ES6 adoption for MOS devs

Some ES6 features we should be using are the use of let and const. These variable declarations work on all modern browsers and even as far back as IE11.

  • First, watch this video on var vs const vs let: Video
  • The above video shows great examples of how and when to use these.
  • Use const or let for all of your references; avoid using var.

Why? This ensures that you can’t reassign your references, which can lead to bugs and difficult to comprehend code.

// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;
  • If you must reassign references, use let instead of var.

Why? let is block-scoped rather than function-scoped like var.

// bad
var count = 1;
if (true) {
  count += 1;
}

// good, use the let.
let count = 1;
if (true) {
  count += 1;
}
  • Note that both let and const are block-scoped.
  // const and let only exist in the blocks they are defined in.
  ...{
    let a = 1;
    const b = 1;
  }
  console.log(a); // ReferenceError
  console.log(b); // ReferenceError

Whitespace & Indenting

  • All code MUST indent using two (2) space characters
// bad
function foo() {
∙∙∙∙let name;
}

// bad
function bar() {
∙let name;
}

// good
function baz() {
∙∙let name;
}
  • Place 1 space before the leading brace.
// bad
function test(){
  console.log('test');
}

// good
function test() {
  console.log('test');
}

// bad
dog.set('attr',{
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});

// good
dog.set('attr', {
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});
  • Place 1 space before the opening parenthesis in control statements (if, while etc.). Place no space between the argument list and the function name in function calls and declarations.
// bad
if(isJedi) {
  fight ();
}

// good
if (isJedi) {
  fight();
}

// bad
function fight () {
  console.log ('Swooosh!');
}

// good
function fight() {
  console.log('Swooosh!');
}
  • Set off operators with spaces.
// bad
const x=y+5;

// good
const x = y + 5;
  • Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which emphasizes that the line is a method call, not a new statement.
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// bad
$('#items').
  find('.selected').
    highlight().
    end().
  find('.open').
    updateCount();

// good
$('#items')
  .find('.selected')
    .highlight()
    .end()
  .find('.open')
    .updateCount();

// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', `translate(${radius + margin},${radius + margin})`)
    .call(tron.led);

// good
const leds = stage.selectAll('.led')
    .data(data)
  .enter().append('svg:svg')
    .classed('led', true)
    .attr('width', (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', `translate(${radius + margin},${radius + margin})`)
    .call(tron.led);

// good
const leds = stage.selectAll('.led').data(data);
  • Do not add spaces inside parentheses.
// bad
function bar( foo ) {
  return foo;
}

// good
function bar(foo) {
  return foo;
}

// bad
if ( foo ) {
  console.log(foo);
}

// good
if (foo) {
  console.log(foo);
}
  • Do not add spaces inside brackets.
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);
  • Add spaces inside curly braces.
// bad
const foo = {clark:'kent'};

// good
const foo = {clark: 'kent'};

Semi-colons

'''Yes, use them.''' JavaScript allows optional "semi-colon insertion". Our standards do not.

  • All statements (except for, function, if, switch, try, while) MUST be followed by a semi-colon (;)
  • Return values MUST start on the same line as the return keyword.

Examples:

// bad - raises exception
const luke = {}
const leia = {}
[luke, leia].forEach(jedi => jedi.father = 'vader')

// bad - raises exception
const reaction = "No! That's impossible!"
(async function meanwhileOnTheFalcon() {
  // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  // ...
}())

// bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI!
function foo() {
  return
    'search your feelings, you know it to be foo'
}

// good
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) => {
  jedi.father = 'vader';
});

// good
const reaction = "No! That's impossible!";
(async function meanwhileOnTheFalcon() {
  // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  // ...
}());

// good
function foo() {
  return 'search your feelings, you know it to be foo';
}

Semi-colon Exception:

  • Anonymous functions assigned to a variable MUST be followed by a semi-colon.
const doSomething = function(context) {
  // Statements...
}; // <-- MUST include semi-colon.

Drupal.behaviors.tableSelect = function(context) {
  // Statements...
}; // <-- MUST include semi-colon.

$(window).load(function() {
  // Statements...
}); // <-- MUST include semi-colon.

Commas

  • Leading commas: '''Nope.'''
// bad
const story = [
    once
  , upon
  , aTime
];

// good
const story = [
  once,
  upon,
  aTime,
];

// bad
const hero = {
    firstName: 'Ada'
  , lastName: 'Lovelace'
  , birthYear: 1815
  , superPower: 'computers'
};

// good
const hero = {
  firstName: 'Ada',
  lastName: 'Lovelace',
  birthYear: 1815,
  superPower: 'computers',
};
  • Additional trailing comma: '''Yup.'''

Why? This leads to cleaner git diffs.

// bad - git diff without trailing comma
const hero = {
     firstName: 'Florence',
-    lastName: 'Nightingale'
+    lastName: 'Nightingale',
+    inventorOf: ['coxcomb chart', 'modern nursing']
};

// good - git diff with trailing comma
const hero = {
     firstName: 'Florence',
     lastName: 'Nightingale',
+    inventorOf: ['coxcomb chart', 'modern nursing'],
};
// bad
const hero = {
  firstName: 'Dana',
  lastName: 'Scully'
};

const heroes = [
  'Batman',
  'Superman'
];

// good
const hero = {
  firstName: 'Dana',
  lastName: 'Scully',
};

const heroes = [
  'Batman',
  'Superman',
];

Comments

  • Comments should end with a full stop (period, exclamation, question mark etc.)
  • Use /** ... */ for multi-line comments.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

  // ...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed-in tag name.
 */
function make(tag) {

  // ...

  return element;
}
  • Use // for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block.
// bad
const active = true;  // is current tab.

// good
// is current tab.
const active = true;

// bad
function getType() {
  console.log('fetching type...');
  // set the default type to 'no type'.
  const type = this.type || 'no type';

  return type;
}

// good
function getType() {
  console.log('fetching type...');

  // set the default type to 'no type'
  const type = this.type || 'no type';

  return type;
}

// also good
function getType() {
  // set the default type to 'no type'.
  const type = this.type || 'no type';

  return type;
}
  • Start all comments with a space to make it easier to read.
// bad
//is current tab.
const active = true;

// good
// is current tab.
const active = true;

// bad
/**
 *make() returns a new element
 *based on the passed-in tag name.
 */
function make(tag) {

  // ...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed-in tag name
 */
function make(tag) {

  // ...

  return element;
}
  • Prefixing your comments with FIXME or TODO helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are FIXME: -- need to figure this out or TODO: -- need to implement.
  • Use // FIXME: to annotate problems.
class Calculator extends Abacus {
  constructor() {
    super();

    // FIXME: shouldn’t use a global here.
    total = 0;
  }
}
  • Use // TODO: to annotate solutions to problems.
class Calculator extends Abacus {
  constructor() {
    super();

    // TODO: total should be configurable by an options param.
    this.total = 0;
  }
}

Objects

  • Use the literal syntax for object creation.
// bad
const item = new Object();
// good
const item = {};
  • Only quote properties that are invalid identifiers. eslint: quote-props jscs: disallowQuotedKeysInObjects

Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines.

// bad
const bad = {
  'foo': 3,
  'bar': 4,
  'data-blah': 5,
};

// good
const good = {
  foo: 3,
  bar: 4,
  'data-blah': 5,
};

Blocks

  • Use braces with all multi-line blocks.
// bad
if (test)
  return false;

// good
if (test) return false;

// good
if (test) {
  return false;
}

// bad
function foo() { return false; }

// good
function bar() {
  return false;
}
  • If you're using multi-line blocks with if and else, put else on the same line as your if block’s closing brace.
// bad
if (test) {
  thing1();
  thing2();
}
else {
  thing3();
}

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}
  • If an if block always executes a return statement, the subsequent else block is unnecessary. A return in an else if block following an if block that contains a return can be separated into multiple if blocks.
// bad
function foo() {
  if (x) {
    return x;
  } else {
    return y;
  }
}

// bad
function cats() {
  if (x) {
    return x;
  } else if (y) {
    return y;
  }
}

// bad
function dogs() {
  if (x) {
    return x;
  } else {
    if (y) {
      return y;
    }
  }
}

// good
function foo() {
  if (x) {
    return x;
  }

  return y;
}

// good
function cats() {
  if (x) {
    return x;
  }

  if (y) {
    return y;
  }
}

//good
function dogs(x) {
  if (x) {
    if (z) {
      return y;
    }
  } else {
    return z;
  }
}

jQuery

  • Prefix jQuery object variables with a $.
// bad
const sidebar = $('.sidebar');

// good
const $sidebar = $('.sidebar');

// good
const $sidebarBtn = $('.sidebar-btn');
  • Cache jQuery lookups.
// bad
function setSidebar() {
  $('.sidebar').hide();

  // ...

  $('.sidebar').css({
    'background-color': 'pink',
  });
}

// good
function setSidebar() {
  const $sidebar = $('.sidebar');
  $sidebar.hide();

  // ...

  $sidebar.css({
    'background-color': 'pink',
  });
}
CSS →
  • Early ES6 adoption for MOS devs
  • Whitespace & Indenting
  • Semi-colons
    • Examples:
    • Semi-colon Exception:
  • Commas
  • Comments
  • Objects
  • Blocks
  • jQuery
Facebook Open Source
Copyright © 2024 Motionstrand