Categories
JavaScript Best Practices

JavaScript Best Practices — Variable Naming Conventions

JavaScript is a very forgiving language. It’s easy to write code that runs but has issues in it.

In this article, we’ll look at best practices for naming JavaScript variables.

When You Should Have a Naming Convention

We need some naming conventions so that everyone working on the project are on the same page.

Also, we run a program over to another person for changes, they’ll also be on the same page.

It also makes reviewing things easier as we don’t have to find out what something means.

When a program is so big that we can’t hold them in brains, then having conventions reduce the cognitive load of our brains.

Informal Naming Conventions

Naming conventions vary between languages, but there’re some that apply to language.

Variable names and functions names are both camelCase except for classes constructor functions, which are named in PascalCases.

Objects are in camelCase.

To make identifying global variables easier, we can put a g prefix before the global variable.

Member variables are named the same as other variables in JavaScript.

But we may put a _ before the member variable of a class to distinguish them from other variables.

Other Conventions for Names in JavaScript

Index variables are named with short names like i and j .

Constants are named with all caps with underscores in between words.

get and set are used for accessor methods.

Property names of objects are also named with camel case.

Parameters of functions are also camel case as with variables.

Standardized Prefixes

We may want to prefix our variables names to make identifying them easier.

To do that, we may add semantic prefixes to some variables to make them easier to understand.

For instance, we may have c for count, first for the first element of an array, g for a global variable, i for array index, and last for the last element of an array.

The m prefix may be used for class instance variables. max for the maximum of a set of numbers, min is the minimum number from an array.

Advantages of Standardized Prefixes

Standardized prefixes give us all the advantages of standard naming conventions,

We don’t have to dig deep to find what something means.

The distinctions between prefixes like min , first , last and max are helpful.

Creating Short Names That Are Readable

If we abbreviate variable names, then we should make sure that they’re abbreviations that everyone understands.

There are many ways to abbreviate variable names.

We can use standard abbreviations.

Nonleading vowels should be removed from abbreviations. For instance, apple becomes appl .

Articles like and , or , the , etc. should be removed.

The first letter or first few letters should be used.

Truncating words consistently may also be used for naming variables.

Using the first and last letters of each word is another possibility.

Every significant word in the name can also be used.

Useless suffixes can also be removed.

These are all possible ways that we can abbreviate variable names.

Phonetic Abbreviations

We can also use phonetic abbreviations. However, it’s not very clear so it’s probably a bad idea to use them.

Good Practices When Abbreviating Variable Names

We shouldn’t abbreviate by removing one character from a word.

Since it’s only one character shorter, it doesn’t help us too much.

Abbreviating consistent is also a good idea. We should keep some conventions to remove our cognitive load.

Creating names that we can pronounce is also good.

Combinations that may result in misreading or mispronunciation also isn’t good. So sEnd is better than send , for example.

A thesaurus can help us resolve naming collisions if we do run into them.

If we have short names, we may want to document them so that people can understand what those names stand for.

A project-level document for names that people might not understand is also a good idea to have.

Conclusion

To make sure that everyone understands the names that we name, we got to name them clearly.

If we abbreviate, then we got to stick to a convention for abbreviation and keep a list of abbreviations if needed.

Categories
JavaScript Best Practices

JavaScript Best Practices- Variable Declarations, IIFEs, and Yoda

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we look at why we should put var declarations on top, wrapping IIFES, and Yoda expressions.

Put Variable Declarations to be at the Top of Their Scope

We should put variable declarations on the top of their scope so that we’re sure that we can access them from the beginning.

One confusing feature of JavaScript is that variables declared with var can be hoisted.

The declaration is hoisted but the value assigned to it is not.

For instance, if we have:

console.log(x)
var x = 1;

Then we should see that x is undefined from the console log output because the var x part is hoisted to the top, but setting the value is still done after the console log call.

var is function scoped, so it’s fine for it to be declared on top of a function block.

But they should all be declared before any code inside is run. So, we shouldn’t have code like:

function foo() {
  var first;
  first = 1;
  var second;
}

In the code above, the second variable is written after the first = 1; expression, so second will be hoisted to the top of the function.

If we log it as follows:

function foo() {
  var first;
  console.log(second);
  first = 1;
  var second = 2;
}

foo()

Then we get that second is undefined since var second is hoisted to the top, but the rest of the expression stays at the bottom.

As we can see, having var variables below the top section of a function or at the top level of a script is a pain. We’ve to know that some part of it is hoisted.

Therefore, we should just put all of the var declarations at the top. If it’s a script, we should put var declarations at the top of the top-level of a script as follows:

var foo = 1;
var bar = 2;
//...

Then we don’t have to worry about hoisting.

Likewise, in functions, we should put all the var declarations on top as follows:

function baz() {
  var foo = 1;
  var bar = 2;
  //...
}

It’s just painful to have them anywhere else. Better yet, we should use let and const instead of var . They’re block-scoped and they aren’t hoisted so that they can only be referenced after they’re defined.

Wrap Our IIFEs

IIFEs are immediately invoked function expressions. They’re functions that are called immediately after they’re declared.

We should wrap them to make sure that we’re calling the function and avoid syntax errors.

For instance, if we have the following code:

const bar = () => ({
  a: 1
})();

The () in the end, we didn’t call the arrow function we declared. And if we log bar , we just get the function itself.

Instead, we should write:

const bar = (() => ({
  a: 1
}))()

The code above wraps the whole function in parentheses. Then when we add the () after it, the function we defined is actually called.

If we want to call a function method like bind , call , and apply right after the function is defined, we can do the following:

const x = (function() {
  return this
}).call({
  a: 1
})

This way, call actually is called on the function we defined.

Therefore, we should always wrap our IIFEs with parentheses so that it’ll be called if we add () after it.

No Yoda Conditions

A condition expression like the following:

if ("apple" === fruit) {
  _// ..._
}

is called a Yoda condition because it reads like ‘if apple equals the fruit’, which like how Yoda in Star Wars speaks.

If we flip the operands in the condition as follows:

if (fruit === "apple") {
  _// ..._
}

Then the condition reads like ‘if the fruit equals apple’, which is more natural for many people.

This is more of a style preference since we may be able to use the = operator instead of === to assign 'apple' to fruit instead of comparing them with the === operator.

But it reads more naturally, so it’s a matter of preference rather than something we should change.

Conclusion

Yoda expressions are things like "apple" === fruit . It’s more of a matter of preference in how we order the operands.

IIFEs should always be wrapped with parentheses so that we make sure it’s always called.

var declarations should always be on top of their scope so that there’s no ambiguity with hoisting.

Categories
JavaScript Best Practices

JavaScript Best Practices — Object Shorthand and Arrow Functions

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at using the object literal shorthand syntax, arrow functions for callbacks, and using const most of the time to prevent accidental reassignment.

Use Object Literal Shorthand Syntax

We should use object literal shorthand syntax for populating our object with properties.

There’re 2 kinds of shorthands that are available for populating object properties in objects.

One is the object property shorthand and the other is the method shorthand.

To use the object property shorthand, we can write something like the following code:

const a = 1,
  b = 2,
  c = 3;

const obj = {
  a,
  b,
  c
};

In the code above, we have constants a , b and c .

Then we populate the obj object with properties a , b and c with the values that are the same as the variables with the same name.

The code above is equivalent to the following code:

const a = 1,
  b = 2,
  c = 3;

const obj = {
  a: a,
  b: b,
  c: c
};

As we can see, we removed duplicate code with the shorthand. It saves us typing and looks cleaner.

For methods, we can declare them with the shorthand as follows. For example, we can add methods to our object with the following code:

const obj = {
  foo() {},
  bar() {}
};

In the code above, we declared the foo and bar methods in the obj object as traditional functions by using the shorthand, which lets us declare traditional functions as methods in our object without using the : and the function keyword.

We know that they’re traditional functions because we can reference this in it. For instance, we can write the following code to do that:

const obj = {
  baz: 'baz',
  foo() {
    console.log(this.baz);
  },
  bar() {}
};

In the code above, we log the value of this.baz , where this is obj in the code above.

Then when we call it as follows:

obj.foo();

We get 'baz' logged in the console. Therefore, we know that this inside the foo method is the obj object, so we know that the foo method is a traditional JavaScript function.

This much shorter than its older equivalent, which is the following:

const obj = {
  baz: 'baz',
  foo: function() {
    console.log(this.baz);
  },
  bar: function() {}
};

As we can see from the code above, we have to type out a lot more characters to declare a method in the code above, the function keyword is 8 extra characters and we have it in both methods.

We can also shorten the declaration of generator functions. The following is the shorthand for declaring a generator method in JavaScript objects:

const obj = {
  * foo() {
    yield 1;
  },
};

The code above has the * symbol to indicate that foo is a generator function rather than a regular function.

It’s shorthand for the following code:

const obj = {
  foo: function*() {
    yield 1;
  },
};

As we can see, it’s much shorter.

Therefore, we should use the shorthands to populate our object properties whenever possible so that we can type less and make our code cleaner while keeping our code clear still.

Using Arrow Functions for Callbacks

Using arrow functions for callbacks is a great idea. We don’t have to worry about the value of this inside an arrow function since it doesn’t mind it.

It’s also less verbose and it binds to the this in their surround scope rather than binding to their own value of this unlike a regular function.

If we don’t need to have a specific value for this in our callbacks, which is most likely the case, then we can use arrow functions for our callbacks.

For instance, instead of writing the following code:

const arr = [1, 2, 3].map(function(x) {
  return x * 2;
})

we can write the following with an arrow function as the callback:

const arr = [1, 2, 3].map(x => x * 2);

As we can see, there’s a big difference in the number of characters in each piece of code. They do the same thing, but the first example is much longer than the 2nd.

We implicitly return x * 2 since we return our result in the first line. Also, we didn’t have to use the function and return keywords to define our function and return something inside.

Since it doesn’t reference a specific value of this , using an arrow function is the right choice.

Conclusion

Whenever we can, we should use the object shorthands to populate the properties of our objects. There’re shorthands for both value properties and methods.

Using arrow function for callbacks is a good choice because it saves lots of typing and doesn’t bind to its own value of this .

Categories
JavaScript Best Practices

JavaScript Best Practices — More About Loops

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at the best practices for writing loops, especially with how we control flow control in loops.

Make Loop-Termination Conditions Obvious

To make our code easier to read, we should make the loop termination conditions obvious.

If we have a for loop, we shouldn’t use break to end the loop. This is because we already have an ending condition at the top of the loop.

We may want to use those for a while loop through since we’ve to end the loop explicitly inside the loop body by setting a flag or using break .

Don’t Mess With the Loop Index of a for Loop to Make the Loop Terminate

The loop counter shouldn’t be modified in the for loop.

Therefore, we shouldn’t set the loop index to be bigger than the end index to stop the loop.

If we want more flexibility, we should use a while loop instead.

Avoid Code that Depends on the Loop Index’s Final Value

We shouldn’t use the final value of the loop index outside the loop.

We may not know what the final value os, and even if we do, it’s just bad to use them since we don’t know what’s going to happen to the variable outside the loop.

Consider Using Safety Counters

A safety counter prevents us from running too many iterations of a loop.

For instance, if we don’t want a loop to run for more than 100 iterations, we can write:

while (node) {  
  if (i === 100) {  
    break;  
  }  
  //...    
  node = node.nex;  
  i++;  
}

In the code above, if we traverse a list for more than 100 iterations, then we end the while loop.

This way, we won’t get a loop that can possibly run forever if the list is circular.

Consider Using break Statements Rather than Boolean Flags in a while Loop

To end a while loop, we may also want to use the break statement to end it.

This is easier than assigning a boolean flag to a different value.

For instance, we can write the following:

while (condition) {  
  if (end) {  
    break;  
  }  
  //...    
  i++;  
}

Then we don’t have to worry about assigning condition to something falsy to end the loop.

Be Wary of a Loop with a lot of breaks Scattered Through it

The more break statements we have, the more we’ve to read and understand.

Therefore, we should minimize the use of break even though we can use it to end the loop.

Also, we don’t want to confuse the break in switch statements with the ones for breaking the loop, so we should keep switch statements out of the loop body.

Use continue for Skipping to the Next Iteration

We can use the continue statement to skip to the next iteration of a loop.

For instance, if we have:

for (let i = 0; i < 10; i++) {  
  if (i === 5) {  
    continue;  
  }  
  //..  
}

In the code above, we have the continue statement to skip the loop body when the i is 5.

Use break and continue Only with Caution

As we mentioned in the previous section, we shouldn’t use break frequently.

This is the same as the continue statement.

It’s just too easy to abuse them by using them too frequently. They’re hard to understand.

If we have too many conditions where we have to end the loop, then the loop is probably doing too much.

Checking Endpoints

We should make sure that we check for off-by-one errors so that we don’t run into them when we’re running a loop.

If our loop does complex calculations, then we should check them to make sure they work properly.

Mental simulations that are hard on our brains should be done on paper.

Use Integers for Limits on Both Arrays and Loops

Array indexes have to be integers, so if we’re looping through a loop with a for loop, then we should use integers for the loop index variable as well.

Otherwise, we may not get the array element that we want.

Conclusion

We should make sure to loop through a loop with an integer index to avoid running into unexpected issues.

Also, we shouldn’t use break and continue to frequently to make our code easier to understand.

Safety counters may also be handy to prevent running a loop for too many iterations.

Categories
JavaScript Best Practices

JavaScript Best Practices — Functions and Parameters

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at some best practices regarding functions and default parameters.

Use Default Parameter Syntax Rather Than Mutating Function Arguments

Default parameters are useful for handling parameters that may not have a value set for it by passing in an argument.

For instance, we can write the following code to define parameters with default values:

const add = (a, b = 0) => a + b;

In the code above, we defined an add function with the parameter b set to 0 by default.

This way, if we don’t pass anything in, we’ll get that b is set to 0. The default parameter is also set if we pass in any falsy value.

For example, if we call the function as follows:

add(1, false);
add(1);

Then we get the same result, which is 1 since b is set to 0.

This is shorter than the old way, which is using the || operator to set the default value of a parameter that may not have a value set to it, which is the following:

const add = (a, b) => {
  b = b || 0;
  return a + b;
}

As we can see, the code is longer, and we have to mutate the parameter b directly so that we can set the default value the parameter. This is longer and mutating variables unnecessarily is bad.

Default parameters have to come after regular parameters. For instance, we should write something like the following if we have multiple parameters:

const add = (a, b = 0, c = 0) => a + b + c;

Then we can call it by writing something like the following:

add(1, false, 2)

and we get 3 as the returned value since b is set to 0.

Avoid Side Effects With Default Parameters

We can run any code with default parameters. This includes running side effects. However, we shouldn’t do that since we don’t want to mutate outside code within functions.

Side effects make our code harder to follow and test. Therefore, we shouldn’t do that.

For instance, if we have the following code:

let b = 1;

const count = (a = b--) => {
  console.log(a);
}

In the code above, we have a function count that mutates b in the default parameter. We can see that b , which is outside the function, is being mutated as we run count .

Each time we run count , b is decremented. So b is 1 when count is first run without an argument passed in and the value is assigned to a . b isn’t returned before -- is run so that the decremented value isn’t assigned to a .

However, when we run count the 2nd time without an argument passed in, we run the code that decrements b again with the decremented value that’s returned from the first run is returned, so 0 is returned to a .

And a is logged as 0. Likewise, when we run it again and again, we get the same result.

Therefore, it’s committing the side effect of mutating the variable b , which is mutating the value of b .

If we run count with an argument, then we get the argument logged.

Always Put Default Parameters Last

Default parameters should be put last so that we can spot them easily. For instance, instead of writing the following code:

const add = (a, b = 0, c, d = 0) => a + b + c + d;

where we have a and c without default values and b and d with default parameter values, then the ones with default parameters are hard to spot.

Instead, we should write the parameters with default parameters all together as follows:

const add = (a, b, c = 0, d = 0) => a + b + c + d;

Conclusion

Default parameters are great for setting default values for parameters without mutating parameters directly in our code.

We should follow best practices when using the default parameter syntax, which is ordering parameters with default values after regular parameters and not running code with side effects in default parameter code.