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.

Categories
JavaScript Best Practices

JavaScript Best Practices — Destructuring

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 how to use the JavaScript destructuring syntax to our advantage.

Use Object Destructuring When Accessing and Using Multiple Properties of an Object

The destructuring syntax is great for setting multiple object properties to variables at the same time.

It saves us from creating temporary references to those properties.

For instance, instead of writing the following to assign our object properties to variable the old way:

const obj = {
  a: 1,
  b: 2
}

const a = obj.a;
const b = obj.b;

We can write the following:

const obj = {
  a: 1,
  b: 2
}

const {
  a,
  b
} = obj;

In the code above, we set the obj.a ‘s value to a and obj.b ‘s value to b with the destructuring syntax. It’s the same as the old way, which requires us to access the object properties individually.

The benefit is that we don’t have to reference obj in every line.

In both examples, we have the value of a being 1 and the value of b being 2.

It also works with function arguments. For instance, we can destructure object parameters into variables by writing the following:

const obj = {
  a: 1,
  b: 2
}

const add = ({
  a,
  b
}) => a + b;
const sum = add(obj);

In the code above, we have the same obj object with properties a and b . We also have the add function, which takes an object with properties a and b and returns the sum of them.

We then pass in obj as an argument of add . The destructuring syntax will then take the value of property a and set it as the value of parameter a and do the same for b .

Therefore, we get 3 as the return value in the example above.

Furthermore, we can do the same thing for objects in arrays. If we use the for...of loop, then we can use the object destructuring syntax as follows:

const arr = [{
    name: 'jane',
    age: 20
  },
  {
    name: 'joe',
    age: 22
  },
];

for (const {
    name,
    age
  } of arr) {
  console.log(name, age);
}

In the code above, we destructured our object in the first line of our for...of loop. We destructured the name and age properties of each entry of arr into the name and age loop variables is updated in each iteration.

Use Array Destructuring

Like with object destructuring, we can destructure arrays the same way. For instance, we can use it as follows:

const [a, b] = [1, 2];

In the code above, we set the variable values by the position that they’re in. So a is set to 1 and b is set to 2.

This is much better than assigning them to variables the old way, which is the following:

const arr = [1, 2];
const a = arr[0];
const b = arr[1];

As we can see, we’ve to write 3 lines to do the same thing. Plus we have to set a name for the array before getting the entries and assigning them to variables.

We didn’t have to do that with the destructuring syntax.

Likewise, we can do the destructure arrays in parameters. For instance, we can write the following code:

const add = ([a, b]) => a + b;
const sum = add([1, 2]);

In the code above, we destructured our array parameter in the add function into variables and return them added together.

Then we can call add with an array in the 2nd line to get the sum of them.

We can also use the syntax in the for...of loop as follows:

const arr = [
  ['a', 1], ['b', 2]
];
for (const [key, val] of arr) {
  console.log(key, val);
}

In the code above, we destructured our array entries in the for...of loop much like how we did it with the object destructuring syntax, so we get:

a 1
b 2

logged in the console.

Conclusion

The destructuring is great for destructuring objects and arrays. We can use it to destructure object property values into individual variables by matching their position and the identifier name.

With arrays, the destructuring is done by matching the position of the array entry with the position of the variable.

Categories
JavaScript Best Practices

JavaScript Best Practices — Variable Scopes

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 declaring variables and using JavaScript variable scopes.

Scope

The scope is where we can access a variable.

JavaScript has several kinds of scopes. Variables declared with var has function scope, and variables declared with let or const has block scope.

var variables can also be hoisted so that the variable can be accessed before it’s defined.

let and const variables and constants aren’t hoisted.

Localize References to Variables

Variables are all local in JavaScript if they’re declared with keywords.

If they’re not, then they’re global. Global variables can only be declared in strict mode.

If it’s on, then we can’t declare them.

Global variables are declared with no keyword.

Therefore, we should stick with let and const for declaring variables and constants.

Keep Variables “Live” for as Short a Time as Possible

We should keep them available for as short a time as possible. This means the lines of code that the variable is available for referencing should be small.

This way, we can’t accidentally assign them to an unexpected value as easily and reduce the chance of errors.

If a variable is only available within the block, then that’s better than having it available outside a block.

That’s another benefit to using let and const since they’re block-scoped and we can be sure that they can’t be referenced before they’re defined.

Also, they won’t be available to any code outside the block.

Short live times make our code more readable since we don’t have to keep so much in our minds.

The chance of initialization errors would be reduced.

We can also split block-scoped variables into smaller functions easily.

General Guidelines for Minimizing Scope

We can minimize the scope of our variables easily.

There’re a few guidelines for minimizing scope below.

Initialize Variables Used in a Loop Immediately Before the Loop

We should declare variables used in a loop immediately before the loop so that we can see where they’re used right away.

If we modify the loop, we’ll remember that the variable is used and we won’t make mistakes with them.

For instance, we can write:

let done = false;  
while (!done) {  
  //...  
}

We have the done variable right before the while loop, so we won’t forget about it when we’re working on the loop.

Don’t Assign a Value to a Variable Until Just Before the Value is Used

The values of a variable shouldn’t be assigned until right before the value is used.

This way, it’s clear where the variable first receives its value, and confusion is minimized.

Group Related Statements

If we have related statements, then we should group them together.

This way, we don’t have to jump back and forth when we ready our code to get the whole workflow.

Break Groups of Related Statements into Separate Functions

Shorter functions have shorter variable spans, which is good for readability.

The scope of variables is reduced so that we don’t have to scroll to read all the places where a variable is accessed.

Begin with Most Restricted Visibility, and Expand the Variable’s Scope Only if Necessary

Block scoped variables is good for restricting visibility. It confines the variables within the block.

We should only expand the scope if we need to since we don’t want to expand the ‘live’ time to minimize the chance of assigning them accidentally and make them harder to read.

Minimizing Scope

Maximizing scope by expanding variable scopes may make them easier to write, but the program is easier to understand since those variables may be referenced anywhere.

That’s not good since we don’t want to do that.

We’ve to look at where all the variables in all places just to understand how one variable is used, which is very bad for readability.

Therefore, minimizing scope is definitely something that we should do.

Conclusion

We should minimize the scope of our variables to make them easier to read.

Variables with smaller scopes can also be moved around easier so that we won’t have a difficult time looking at them at all the places that they’re used.

Therefore, block scope variables and constants are good. We can declare them with let and const respectively.