October 27, 2021

Bad JavaScript Practices That’s Letting Your Code Down

Bad JavaScript Practices That’s Letting Your Code Down

We’ve all done it — but the question is, are you still coding it?

JavaScript is easy — especially if you’ve already got programming knowledge and experience through another language. Many newbies and veteran developers encounter JavaScript out of necessity. A good portion of the Internet runs on some form of JavaScript. The frontend has its frameworks and libraries such as Angular, React, and Vue. Backend is dominated by node.js, Next.js, Express, Gatsby, and Meteor.

Whatever the case, JavaScript is here to stay.

By design, JavaScript is easy to pick up and just work. There’s no main() class to set up, no special functions required to run - just the right file extension and we're good to go. Libraries and frameworks exist to make our coding lives easier by encapsulating patterns, good architectural practices, and streamline modes of thought for code scalability and cohesiveness.

But there are little things that we do to sabotage our code. Most of the time, we don’t even notice it. Here are four common bad JavaScript practices that exist in every repository in some form — if not in the past, then in the present git commit.

Normal function vs Arrow function

We all know what a normal function looks like. We also know what an arrow function looks like. But many of us don’t know what’s the actual functionality and differences are between a normal function and an arrow function.

While a normal function and arrow function appear to be doing the same thing, the major impact it has on your code is how argument binding works.

Arrow functions don’t have arguments binding.

For example:

let normalFunc = {
   showMeTheMoney(){
     console.log(arguments)
   }
 }
 ​
 let arrowFunc = {
   showMeTheMoney : () => console.log(arguments)
 }
 ​
 normalFunc.showMeTheMoney(10)
 arrowFunc.showMeTheMoney(10)

normalFunc.showMeTheMoney(10) will return:

[object Arguments] {
   0: 10
 }

Meanwhile, arrowFunc.showMeTheMoney(10) will return:

error ReferenceError: arguments is not defined

Another feature difference between normal and arrow function is how new keyword works.

Regular functions are constructible. Arrow functions are only callable. This means that you can only use the new keyword to construct a new object with regular functions.

For example:

let normalAdd = function(x,y){
   console.log(x + y)
 }
 ​
 let arrowAdd = (x, y) => console.log(x + y);
 ​
 ​
 ​
 new normalAdd(1,2);
 new arrowAdd(1,2);

normalAdd(1,2) will return 3 while arrowAdd(1,2) will return:

error 
TypeError: arrowAdd is not a constructor

And finally, you’re not allowed to have duplicate names in arrow functions.

For example, this is perfectly valid in JavaScript for normal functions when not using strict mode:

function random(z,z){}

However, this is not:

let random = (z,z) => {}

That’s basically the main difference between normal and arrow functions.

let vs var

Like normal and arrow functions, many developers don’t know the difference between let and var. It's 2021 (or 2022 onwards, depending on when you've stumbled onto this). We've is saying use let - but why?

In a nutshell, var is function scoped. let is block-scoped - that is, variable accessibility is limited to the closest {} pair.

this

this keyword is prevalent in JavaScript and a lot of developers still don't quite have their head around how it works.

The easiest way to think about it is that let and var has access to child variables but no access variable beyond their scoped block. this lets you go up a level.

Here’s a quick diagram I drew for a different article I’ve published earlier on let, var, and this.

array methods

There is a lot of code I’ve encountered that uses various loops and funky nesting to achieve simple tasks like sorting, slicing, filtering, and finding certain things in an array.

Using array methods simplifies the code and makes your JavaScript much slimmer. while and for loops may work, but they're inefficient, harder to replicate in a modular manner, and there's no standardized way of enforcing change. Not only that, if something goes wrong and the process hasn't finished, the function that relies on the value also breaks as a side effect.

There are 6 main array methods that we use — filter(), find(), map(), reduce(), every(), and some(). Here are code samples on how to use them.

Using filter() in JavaScript

let animals = [
     {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
     {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
     {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
   ]
 ​
  /*using functional filter() where a represents an item in the array*/
  let neuteredAnimals = animals.filter((a) => {
      return a.isNeutered;
  });

Using find() and filter() in JavaScript

let animals = [
     {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
     {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
     {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
   ]
 ​
 animalTypeFound = animals.find( animal => animal.type === 'cat' );
 ​
 // animalTypeFound will return:
 // {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2}
 ​
 animalTypeFilter = animals.filter( animal => animal.type === 'cat' );
 ​
 // animalTypeFilter will return:
 // [{name: 'Tibbers', type: 'cat', isNeutered: true, age: 2}, {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}]

Using map() in JavaScript

let animals = [
     {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
     {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
     {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
   ]
 ​
 // what you need: 
 // ['Tibbers', 'Fluffball', 'Strawhat']
 ​
 let animalNames = animals.map(animal => {return animal.name});
 ​
 // what you need: 
 // [{name: 'Tibbers', species: 'cat'}, {name: 'Fluffball', species: 'rabbit'}, {name: 'Strawhat', species: 'cat'}]
 ​
 let petDetails = animals.map(animal => {
     return {
         name: animal.name, 
         species: animal.type
     };
 });

Using reduce() in JavaScript

let animals = [
     {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
     {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
     {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
   ]
 ​
 // How old are all the animals combined?
 // 0 is the starting value and acts as the first acculmulator value
 // will return 8
 ​
 let totalAge = animals.reduce((acculmulator, animal) => {
     return acculmulator + animal.age;
 }, 0);
 ​
 // lets say you want to find out the oldest animal 
 // code below will return {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
 ​
 let oldestPet = animals.reduce((oldest, animal) => {
     return (oldest.age || 0) > animal.age ? oldest : animal;
   }, {});
 ​
   // decrypting the code above and how terniaries work 
   // the condition --> (oldest.age || 0) > animal.age 
   // if true --> ? oldest
   // else --> : animal

Using every() in JavaScript

let animals = [
     {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
     {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
     {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
   ]
 ​
 let allNeutered = animals.every(animal => {return animal.isNeutered});
 ​
 //will return false because not all values under isNeutered evaluates to true

Using some() in JavaScript

let animals = [
     {name: 'Tibbers', type: 'cat', isNeutered: true, age: 2},
     {name: 'Fluffball', type: 'rabbit', isNeutered: false, age: 1},
     {name: 'Strawhat', type: 'cat', isNeutered: true, age: 5}
   ]
 ​
 let someAreCats = animals.some(animal => {return animal.type === 'cat'});
 ​
 // will return true because at least one animal.type returned 'cat'

These code snippets are from another article I wrote a while back. If you want an in-depth explanation of how they work, you can read it here.

Array Methods: filter, find, map, reduce, every, and some in JavaScript
Not everything is an object. When it comes to functional programming, it’s more to do with the processes that get you from point A to point B than how data and groups of business logic are structured. JavaScript is a language that’s prone to imperative patterns because of

Wrap up: Using JavaScript

This is just the surface of things JavaScript developers don’t use or properly understand. Hopefully, this article helps bring awareness to common things that you might be doing when writing code and help the community become better JavaScript developers.

If you’ve found this piece useful or want to add a common bad practice, feel free to comment below. Thank you for reading.