Categories
JavaScript Best Practices

JavaScript Best Practices — JSX Spacing and Indentation, Fragments, Lists

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

One Function Type for Function Components

We can stick with one function type for function components.

We can either write a regular or an arrow function.

For instance, we can write:

const Foo = function (props) {  
  return <div>{props.content}</div>;  
};

or:

const Foo = (props) => {  
  return <div>{props.content}</div>;  
};

Arrow functions are slightly shorter.

So we may want to just use that for all components.

Boolean Attributes Notation in JSX

If we have a boolean prop and we want to set it to true , we don’t have to write out the value.

For instance:

const Foo = <Bar personal />;

is the same as:

const Foo = <Bar personal={true} />;

We can just stick with the short way.

Spaces Inside of Curly Braces in JSX Attributes and Expressions

We can specify spaces in JSX attributes and expressions explicitly.

For instance, we can write:

<div>  
  hello  
  {' '}  
  <a>world</a>  
</div>

We put the space string in curly braces to make it explicit.

Closing Bracket Location in JSX

We can put closing brackets in a logical location with our JSX code.

For instance, we can write:

<Greeting firstName="jane" lastName="jones" />;

or:

<Greeting  
  firstName="jane"  
  lastName="jones"  
/>;

They’re both aligned logically.

Closing Tag Location in JSX

We should put closing tags in a location that makes it neat.

For instance, we can write:

<Greeting>  
  james  
</Greeting>

or:

<Greeting>james</Greeting>

to make it neat.

No Unnecessary Curly Braces in JSX Props and/or Children

We don’t need curly braces for string props on children.

For instance, the braces are redundant in the code below:

<Greeting>{'hello'}</Greeting>;  
<Greeting prop={'hello'} attr={"foo"} />;

We can clean them up by writing:

<Greeting>hello</Greeting>;  
<Greeting prop='hello' attr='foo' />;

Linebreaks in Curly Braces in JSX Attributes and Expressions

We should write curly braces in a neat manner.

For example, we can write:

<div>  
  { bar }  
</div>

or:

<div>  
  {  
    bar  
  }  
</div>

They’re both symmetrical.

Spaces Inside of Curly Braces in JSX Attributes and Expressions

We should have an even amount of spaces at each end of the expression.

For instance, instead of writing:

<Greeting name={ firstname} />;  
<Greeting name={firstname } />;

We write:

<Greeting name={firstname} />;

Spaces Around Equal Signs in JSX Attributes

We don’t need spaces around the equal signs in JSX attributes.

For instance, we can write:

<Greeting name={firstname} />;

Position of the First Prop

We can put the first prop inline or below the tag name.

For instance, we can write:

<Hello  
   foo  
/>

or:

<Hello foo />

Shorthand or Standard form for React fragments

Fragments are components that don’t render an element and can be used as a wrapper component.

It has a long and short form.

The long-form is <React.Fragment>...</React.Fragment> and the short form is <>...</> .

For instance, we can write:

<React.Fragment><Foo /></React.Fragment>

or:

<><Foo /></>

The long-form can have props and the short form can’t.

Event Handler Naming Conventions in JSX

Event handler prop names should start with on and the function for handling the event should start with handle .

For instance, we can write:

<Foo onChange={this.handleChange} />

or:

<Foo onChange={this.props.onBar} />

The prop names start with on and the handler method starts with handle .

JSX Indentation

We need some indentation in our JSX code.

For instance, we can write:

<App>  
  <Foo />  
</App>

to have 2 spaces for indentation.

It’s easy to read and type.

Props Indentation in JSX

We can use 2 spaces for indenting props as well.

For instance, we can write:

<Greeting  
  firstName="james"  
/>

Add Key Prop to List Items

For React to keep track of list items properly, we need a unique value for each item as the key prop’s value.

This way, React can identify the items properly no matter where it’s located.

For instance, instead of writing:

data.map(x => <Hello>{x.name}</Hello>);

We write:

data.map(x => <Hello key={x.id}>{x.name}</Hello>);

Conclusion

We should remember to add the key prop for list items.

Good spacing and indentation make reading code easier.

We can use strings with spaces to make spaces explicit.

Categories
JavaScript Best Practices

JavaScript Best Practices — Better DOM, String, and Array Methods

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

Use .flatMap(…) over .map(…).flat()

We use flatMap over map and flat together since we can do both things with flatMap ,

for instance,e instead of writing:

[1, 2, 3].map(i => [i]).flat();

We write:

[1, 2, 3].flatMap(i => [i]);

Use .includes() Instead of .indexOf() When Checking for Existence or Non-Existence

includes is better than indexOf when checking for existence or nonexistence.

includes is shorter.

So instead of writing:

[].indexOf('foo') !== -1;

We write:

[].includes('foo');

Use Modern DOM APIs

We should use newer DOM methods than older ones.

For instance, instead of writing:

foo.replaceChild(baz, bar);

foo.insertBefore(baz, bar);

foo.insertAdjacentText('position', bar);

foo.insertAdjacentElement('position', bar);

We write:

foo.replaceWith(bar);

foo.before(bar);

foo.prepend(bar);

foo.append(bar);

Use Negative Index over .length - index for slice and splice

Negative indexes are shorter than length — index for slice and splice .

For instance, instead of writing:

foo.slice(foo.length - 3, foo.length - 1);
foo.splice(foo.length - 1, 1);

We write:

foo.slice(-3, -1);
foo.splice(-1, 1);

It’s much shorter and easier on our brains.

Use Node#append() Over Node#appendChild()

We should use append over appendChild for appending elements to a parent,.

append lets us append strings in addition to nodes.

append has a node return value.

And we can append several nodes and strings with it.

For instance, instead of writing:

foo.appendChild(bar);

We write:

foo.append(bar);
foo.append(bar, 'baz');

Use childNode.remove() over parentNode.removeChild(childNode)

We can use remove to remove a node directly instead of getting the parent and call removeChild to remove a node.

For instance, instead of writing:

parentNode.removeChild(foo);

We write:

foo.remove();

Use Number Static Properties Over Global Ones

The number static properties are better than the global ones.

Number.isNaN and Number.isFinite don’t convert the type of the argument before doing the check.

For instance, instead of writing:

const foo = parseInt('20', 2);
const foo = parseFloat('30.5');
const foo = isNaN(20);
const foo = isFinite(20);
if (Object.is(foo, NaN)) {}

We write:”

const foo = Number.parseInt('20', 2);
const foo = Number.parseFloat('30.5');
const foo = Number.isNaN(20);
const foo = Number.isFinite(20);
if (Object.is(foo, Number.NaN)) {}

Use catch Binding Parameter

If catch ‘s binding parameter isn’t used, then it should be omitted.

So instead of writing:

try {} catch (error) {}

We write:

try {} catch {}

Use .querySelector() Over .getElementById(), .querySelectorAll() Over .getElementsByClassName() and .getElementsByTagName()

querySelector is more versatile than getElementById since the former can take any selector.

querySelectorAll is more versatile than getElementsByClassName and getElementsByTagName since it takes any selector.

So instead of writing:

document.getElementById('baz');
document.getElementsByClassName('baz bar');
document.getElementsByTagName('main');

We write:

document.querySelector('main #baz .bar');
document.querySelectorAll('.baz .bar');

Use Reflect.apply() over Function#apply()

Reflect.apply is shorter and easier to understand than Function.apply .

And we know that it can never be overridden unlike Function.apply .

So instead of writing:

function foo() {}

foo.apply(null, [42]);

We write:

function foo() {}

Reflect.apply(foo, null, [42]);

Use String#replaceAll() Over Regex Searches with the Global Flag

replaceAll is easier to understand than regex search and replace to replace substrings.

For instance, instead of writing:

string.replace(/foo/g, '');

We write:

string.replaceAll('foo', '');

Use Set#has() Over Array#includes() when Checking for Existence or Non-existence

We can use has instead of includes to check for existence or nonexistence since it’s faster.

For instance, instead of writing:

const array = [1, 2, 3, 4, 5];
const hasValue = value => array.includes(value);

We write:

const set = new Set([1, 2, 3, 4, 5]);
const hasValue = value => set.has(value);

Use the Spread Operator Over Array.from()

We should use the spread operator over Array.from .

It’s a shorter way to turn array-like objects to arrays.

For instance, instead of writing:

Array.from(set).filter(() => {});

We write:

[...set].filter(() => {});

Use String#startsWith() & String#endsWith() to Check for Start and End of Strings

We should use startsWith or endsWith to check that a string starts or ends with a given string.

For instance, instead of writing:

/^bar/.test(foo);
/bar$/.test(foo);

We write:

foo.startsWith('bar');
foo.endsWith('bar');

Conclusion

We should use modern JavaScript methods to make our lives easier.

There are many strings and array methods to make our lives much easier.

We should also take note of new DOM method and use those instead of what’s available before.

Categories
JavaScript Best Practices

JavaScript Best Practices — Names, Variables, and Functions

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

Use Meaningful and Pronounceable Variable Names

Meaning and pronounceable variable names are good.

For instance, we should write:

const currentDate = new Date();

instead of:

const yyyymmd = new Date();

Use the Same Vocabulary for the Same Type of Variable

We should use the same vocabulary for the same type of variable.

For instance, we shouldn’t have 3 names of a user.

Instead of writing:

getUserInfo();
getPersonData();
getSubscriberRecord();

for functions to get user data, we should write:

getUser();

to get user data.

Use Searchable Names

We should use searchable names.

This rules out names that are too short or too generic.

Also, we shouldn’t have magic numbers.

For instance, we shouldn’t write:

setTimeout(doSomething, 86400000);

Instead, we write:

const DAY_IN_MILLISECONDS = 86_400_000;

setTimeout(doSomething, DAY_IN_MILLISECONDS);

Use Variables to Explain

We should make variable names that explain what they hold.

For instance, we should write:

const phone = "555-555-1212";
const [areaCode, exchangeCode, lineNumber] = phone.split('-');

Now we know a phone number can be split into those numbers.

No Mental Mapping

We should avoid the need to map with our mind to the meaning of the variable.

For instance, we shouldn’t write:

phoneNumbers.forEach(p => {
  call(p);
});

We’ll forget what p means quickly.

Instead, we write:

phoneNumbers.forEach(phoneNumber => {
  call(phoneNumber);
});

Now we know the parameter for the callback is the phone number without thinking.

No Unneeded Context

We can add too much information in our identifier names.

For instance, if we have:

const car = {
  carMake: "Ford",
  carModel: "Fiesta",
  carColor: "Blue"
};

We don’t need car in front of every property name.

Instead, we write:

const car = {
  make: "Ford",
  model: "Fiesta",
  color: "Blue"
};

We know that the object holds data of a car without mentioning it in every property.

Use Default Arguments

Default arguments are much better than short-circuiting or conditionals for setting default argument values.

For instance, instead of writing:

function createPerson(name) {
  const personName = name || "james";
  // ...
}

We write:

function createPerson(name = 'james') {
  // ...
}

It’s shorter to use default arguments.

Also, || returns 'james' for all falsy arguments like empty string, null , undefined , 0 or NaN .

2 or Fewer Function Arguments Ideally

The more function arguments we have, the harder it is to use it.

We lose track of the data types and their order easily if there are more.

If we need more, we can use object parameter with destructuring, then we don’t have to worry about the order.

And we can have as many arguments as we want.

For instance, instead of writing:

function createCar(make, body, color, lengthInMeters) {
  // ...
}

createMenu("ford", "fiesta", "red", 5);

We write:

function createCar({ make, body, color, lengthInMeters }) {
  // ...
}

createCar({
  make: "ford",
  body: "fiesta",
  color: "red",
  lengthInMeters: 5
});

We pass in an object and destructure the properties to variables in the parameter.

Functions Should do One Thing

Functions that do more than one thing isn’t good.

It’s confusing and probably long.

Therefore, they should do one thing.

For instance, we should write:

function emailActiveCustomers(customers) {
  clients.filter(customerRecord).forEach(email);
}

function isActiveCustomer(customer) {
  const customerRecord = database.lookup(customer);
  return customerRecord.active;
}

instead of:

function emailClients(customers) {
  clients.forEach(customer => {
    const customerRecord = database.lookup(customer);
    if (customerRecord.active()) {
      email(client);
    }
  });
}

The emailClients function both checks if a customer is active and emails the customer.

We should split them to isAcriveCustiomer to check if a customer is active and emailActiveCustomer to email the customer.

Names Functions by What they do

We should name functions in a way that tell what they do.

For instance, instead of writing:

function add(date, years) {
  // ...
}

const date = new Date();

add(date, 1);

We write:

function addYearsToDate(date, years) {
  // ...
}

const date = new Date();

addYearsToDate(date, 1);

addYearsToDate is much clearer than add .

Conclusion

We should name variables and functions clearly.

Also, we should make names meaningful.

Functions should do one thing and not have too many arguments.

If we need more arguments, then we can accept an object and destructure it so that we don’t have to worry about the order they’re passed in.

Categories
JavaScript Best Practices

JavaScript Best Practices — No Useless Syntax

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

No await Without Promises

We should use await only with promises.

It’s definitely an error if we use await with anything else.

For instance, instead of writing:

async function foo(){
  return 10;
}

We write:

async function foo(){
  const val = await aPromise;
}

No Comma Operator

We should never use the comma operator.

All it does is return the last thing in the list.

So instead of writing”

switch (foo) {
  case 1, 2, 3:
    return true;
  case 4, 5:
    return false;
}

We write:

switch (foo) {
  case 3:
    return true;
  case 5:
    return false;
}

Use Curly Braces for if, for, do, or while Statements

We should use curly braces for these statements so that we know where block starts or ends.

Instead of writing:

if (foo === 'baz')
  foo = 10;

We write:

if (foo === 'baz') {
  foo = 10;
}

This way, if we have anything below it, we won’t mistaken it to be within the block.

for-in Should have Filtered with an if Statement

If we write a for-in loop, we should filter out the inherited properties with hasOwnProperty .

For instance, instead of writing:

for (let key in obj) {
  // do something
}

We write:

for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
    // do something
  }
}

No Function Constructor

We shouldn’t use the Function constructor for creating functions.

The code is in a string, which means we can’t analyze or optimize it.

And it’s also a security risk.

So instead of writing:

let multiply = new Function('a', 'b', 'return a * b');

We write:

let multiply = (a: number, b: number) => a * b

Use of Labels

Labels are only meant to be used with do , for , while , or switch statements.

They’re used with break or continue to control loops.

For instance, we write:

A:
  while (foo) {
    if (bar) {
      continue A;
    }
  }

We labeled the loop with A .

Then we used continue on it, which is run if bar is true .

Don’t Use argument Properties

We shouldn’t use arguemnt.callee to get the function that calls the function.

It makes optimization impossible.

It’s also disallowed in strict mode.

No async Without await

We shouldn’t use async without await .

If there’s no await , which means we aren’t using any promises in the function.

Then that means we don’t need it.

So instead of writing:

async function f() {
  doSomething();
}

We write:

async function f() {
  await makeRequest();
}

where makeRequest is a function that returns a promise.

No Assignment in Conditionals

Assigning values in conditions without comparison or other boolean expressions is probably a mistake.

So we should check for those.

For instance, if we have:”

if (foo == bar ){
  //...
}

We should make sure that it’s valid.

No Duplicate super Calls

In a subclass’s constructor , we only need to call super once.

If we call it more than once, we’ll get an error.

For instance, instead of writing:

class Foo extends Bar {
  constructor() {
    super(name);
    super(name);
  }
}

We write:

class Foo extends Bar {
  constructor() {
    super(name);
  }
}

No Duplicate Switch Cases

We should never have more than one case statement with the same value in a switch block.

Only the first case will be run because of short-circuiting.

For instance instead of writing:

switch (bar) {
  case 1:
    return 'foo';
  case 1:
    return 'bar';
  case 2:
    return 'baz';
}

We write:

switch (bar) {
  case 1:
    return 'foo';
  case 2:
    return 'baz';
}

No Duplicate Variable

We should never have duplicate variables in our code.

var declarations can have duplicates that aren’t picked by the JavaScript interpreter.

So we make sure that we don’t have things like:

var a = 1;
var a = 2;

We should remove one of them, or better yet, use let or const instead of var .

Conclusion

We shouldn’t have duplicate var declarations or case blocks.

Curly braces help with delimiting blocks.

await should only be used with promises.

Categories
JavaScript Best Practices

JavaScript Best Practices — Arrays, Todos, and Callbacks

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

Add Expiration Conditions to TODO Comments

If we have todo comments, we can add expiration conditions to it so that ESLint will pick them up and throw an error if they expired.

For instance, we can write:

// TODO [2019-11-15]: fix this

We have the date in ISO 8601 format and the task description.

Explicitly Comparing the length Property of a Value

Explicitly comparing the length property of value is clearer than not.

For instance, instead of writing:

if (string.length) {}
if (array.length) {}

We write:

if (string.length > 0) {}
if (array.length > 0) {}

to compare them against 0 explicitly.

Case Style for Filenames

The case style for filenames should be consistent.

For instance, we can use kebab case for everything:

foo-bar.js

Or we can use camel case.

For instance, we can write:

fooBar.js

Or we can use snake case:

foo_bar.js

Or we can use pascal case:

FooBar.js

Importing Index Files with .

If we’re importing an index.js file, we don’t need to write the file name explicitly.

For instance, instead of writing:

const module = require('./index');

or:

const module= require('./');

We write:

const m = require('.');

or:

const m = require('./foo');

Usenew for all Built-in Constructors, Except String, Number and Boolean

Almost all constructors need the new keyword except for the String , Number , and Boolean ,

We shouldn’t use constructors top create primitive values

Instead, we use them without new :

const str = String(123);

But we write:

const list = new Array(10);

This is because using new with String , Number , or Boolean create objects instead of primitive values.

Use Array.isArray() instead of instanceof Array

Array.isArray is more robust that instanceof Array .

instanceof Array doesn’t work across realms or context.

It doesn’t work between different frames or windows in browsers or the vm module in Node.

For instance, instead of writing:

array instanceof Array;

We write:

Array.isArray(array);

No Leading Space Between console.log Parameters

We don’t need leading space between console.log parameters.

We just put the trailing space.

So instead of writing:

console.log('abc' , 'def');

We write:

console.log('abc', 'def');

Passing a Function Reference Directly to Iterator Methods

We should create our own callback instead of passing the function reference it directly.

For instance, instead of writing:

[1, 2, 3].map(fn);

We write:

[1, 2, 3].map(c => fn(c)));

This way, we can control what parameters are passed in to fn instead of always passing the array entry as the first argument, the index as the 2nd argument, and the array as the 3rd argument.

This also applies to any other function call that takes callbacks.

We want to control the arguments we pass in by creating our own function,

Do not use a for Loop that can be Replaced with a for-of Loop

If we can use a for-of loop to iterate through an object, then we should do so.

For instance, instead of writing:

for (let index = 0; index < arr.length; index++) {
  const element = arr[index];
  console.log(element);
}

We write:

for (const element of array) {
  console.log(element);
}

It’s much cleaner.

Use Unicode Escapes Instead of Hexadecimal Escapes

We should use Unicode escapes instead of hex escapes for clarity and consistency.

For instance, instead of writing:

const foo = 'x1B';

We write:

const foo = 'u001B';

No Nested Ternary Expressions

Nested ternary expressions are hard to read, so we shouldn’t have them.

For instance, instead of writing:

const foo = i > 39 ? i < 100 ? true : true: false;

We wrote:

const foo = (x === 1) ? 'foo' : 'bar';

Conclusion

We should use Unicode escapes instead of hex escapes in a regex.

Ternary expressions are hard to read, so we shouldn’t have them.

ESLint can check for the expiration date of todo comments.

File names casing should be consistent.

We should define our own callbacks instead of passing in a function reference.

The for-of loop is much better than a for loop for looping through iterable objects.