This is a translation + excerpt of the notes! The original:
Github.com/ryanmcdermo…
    

variable

Use meaningful and understandable variable names

bad:

const yyyymmdstr = moment().format("YYYY/MM/DD");Copy the code

good:

const currentDate = moment().format("YYYY/MM/DD");Copy the code

Use explanatory variables

Bad:

const address = "One Infinite Loop, Cupertino 95014"; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?) \s*(\d{5})? $/; saveCityZipCode( address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2] );Copy the code

Good:

const address = "One Infinite Loop, Cupertino 95014"; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?) \s*(\d{5})? $/; const [, city, zipCode] = address.match(cityZipCodeRegex) || []; saveCityZipCode(city, zipCode);Copy the code

Avoid using implicit mappings

Bad:

const locations = ["Austin"."New York"."San Francisco"];
locations.forEach(l => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  // Wait, what is `l` for again?
  dispatch(l);
});Copy the code

Good:

const locations = ["Austin"."New York"."San Francisco"];
locations.forEach(location => {
  doStuff();
  doSomeOtherStuff();
  // ...
  // ...
  // ...
  dispatch(location);
});Copy the code

Don’t add unnecessary content

Bad:

const Car = {
  carMake: "Honda",
  carModel: "Accord",
  carColor: "Blue"
};

function paintCar(car) {
  car.carColor = "Red";
}Copy the code

Good:

const Car = {
  make: "Honda",
  model: "Accord",
  color: "Blue"
};

function paintCar(car) {
  car.color = "Red";
}Copy the code

function

The function has less than or equal to two parameters

It is necessary to limit the number of arguments to your function to make it easier to test your function. Ideally, the number of arguments to a function should be less than two. If it is more than two, your function is doing too much, violating the principle of single-function design.

Bad:

function createMenu(title, body, buttonText, cancellable) {
  // ...
}Copy the code

Good:

function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}

createMenu({
  title: "Foo",
  body: "Bar",
  buttonText: "Baz",
  cancellable: true
});Copy the code

Do not use flags as arguments to functions

Function functionality should remain single function.

bad

function createFile(name, temp) {
  if (temp) {
    fs.create(`./temp/${name}`);
  } else{ fs.create(name); }}Copy the code

good

function createFile(name) {
  fs.create(name);
}

function createTempFile(name) {
  createFile(`./temp/${name}`);
}Copy the code

Use default parameters

Bad:

function createMicrobrewery(name) {
  const breweryName = name || "Hipster Brew Co.";
  // ...
}Copy the code

Good:

function createMicrobrewery(name = "Hipster Brew Co."{/ /... }Copy the code

Functions should only handle functionality at the same level of abstraction

When you have a function that handles multiple levels of functionality, your function is too complex. You should break up functions into layers for easy reuse and testing.

Bad:

functionparseBetterJSAlternative(code) { const REGEXES = [ // ... ] ; const statements = code.split("");
  const tokens = [];
  REGEXES.forEach(REGEX => {
    statements.forEach(statement => {
      // ...
    });
  });

  const ast = [];
  tokens.forEach(token => {
    // lex...
  });

  ast.forEach(node => {
    // parse...
  });
}Copy the code

Good:

function parseBetterJSAlternative(code) {
  const tokens = tokenize(code);
  const syntaxTree = parse(tokens);
  syntaxTree.forEach(node => {
    // parse...
  });
}

functiontokenize(code) { const REGEXES = [ // ... ] ; const statements = code.split(""); const tokens = []; REGEXES.forEach(REGEX => { statements.forEach(statement => { tokens.push(/* ... * /); }); });return tokens;
}

functionparse(tokens) { const syntaxTree = []; tokens.forEach(token => { syntaxTree.push(/* ... * /); });return syntaxTree;
}Copy the code

Avoid side effects

A function can have side effects unless it only reads arguments and then returns another argument

Bad:

// Global variable referenced by following function.
// If we had another function that used this name, now it'd be an array and it could break it. let name = "Ryan McDermott"; function splitIntoFirstAndLastName() { name = name.split(" "); } splitIntoFirstAndLastName(); console.log(name); / / ['Ryan', 'McDermott'].Copy the code

Good:

function splitIntoFirstAndLastName(name) {
  return name.split("");
}

const name = "Ryan McDermott";
const newName = splitIntoFirstAndLastName(name);

console.log(name); // 'Ryan McDermott'; console.log(newName); / / /'Ryan'.'McDermott'];Copy the code

Bad:

const addItemToCart = (cart, item) => {
  cart.push({ item, date: Date.now() });
};Copy the code

Good:

const addItemToCart = (cart, item) => {
  return [...cart, { item, date: Date.now() }];
};Copy the code

Encapsulating conditional statement

Bad:

if (fsm.state === "fetching" && isEmpty(listNode)) {
  // ...
}Copy the code

Good:

function shouldShowSpinner(fsm, listNode) {
  return fsm.state === "fetching" && isEmpty(listNode);
}

if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
  // ...
}Copy the code

Avoid negative statements

Bad:

function isDOMNodeNotPresent(node) {
  // ...
}

if(! isDOMNodeNotPresent(node)) { // ... }Copy the code

Good:

function isDOMNodePresent(node) {
  // ...
}

if (isDOMNodePresent(node)) {
  // ...
}Copy the code

Objects and data structures

Use setters and getters

  • When you want to do more than just get an object property, you don’t need to find and change every accessor in the code base.
  • Makes it easy to add validation when executing a collection.
  • Encapsulate the internal representation.
  • Easy to add logging and error handling when getting and setting.
  • Properties of an object can be lazily loaded, for example from a server.

Bad:

function makeBankAccount() {/ /...return {
    balance: 0
    // ...
  };
}

const account = makeBankAccount();
account.balance = 100;Copy the code

Good:

function makeBankAccount() {
  // this one is private
  let balance = 0;

  // a "getter", made public via the returned object below
  function getBalance() {
    return balance;
  }

  // a "setter", made public via the returned object below
  function setBalance(amount) {
    // ... validate before updating the balance
    balance = amount;
  }

  return{/ /... getBalance,setBalance
  };
}

const account = makeBankAccount();
account.setBalance(100);Copy the code

class

Use chain calls

Bad:

class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
  }

  setModel(model) {
    this.model = model;
  }

  setColor(color) {
    this.color = color;
  }

  save() {
    console.log(this.make, this.model, this.color);
  }
}

const car = new Car("Ford"."F-150"."red");
car.setColor("pink");
car.save();Copy the code

Good:

class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
    // NOTE: Returning this for chaining
    return this;
  }

  setModel(model) {
    this.model = model;
    // NOTE: Returning this for chaining
    return this;
  }

  setColor(color) {
    this.color = color;
    // NOTE: Returning this for chaining
    return this;
  }

  save() {
    console.log(this.make, this.model, this.color);
    // NOTE: Returning this for chaining
    return this;
  }
}

const car = new Car("Ford"."F-150"."red").setColor("pink").save();Copy the code