10 things you're doing wrong with JavaScript

JavaScript is an essential part of the modern web. But like any technology this language has some awkward corners.

Bcorp Logo
10 things you're doing wrong with JavaScript

JavaScript is an essential part of the modern web. But like any technology this language has some awkward corners.

Man of Constant Sorrow

Does a Constant do exactly what it says on the tin? These number and string constants do behave as expected. They cannot be reassigned. Attempting to change them throws a run-time error.

const ARTIST = "Bob Dylan";
const BORN = 1941;
ARTIST = "Dave Smith"; // Error
BORN = 1984; // Error

...but things become more nuanced when we work with objects and arrays:

const CAPITAL = { name:"Rome",temp:24 };

We cannot reassign this object constant.

CAPITAL = { name:"Paris",temp:17 }; // Error

But we can change its contents. This code does not throw an error.

CAPITAL.name = "Paris";
CAPITAL.temp = 28;

The same behaviour applies to constant Arrays.

const LOTTO = [4,5,6,7];

We cannot reassign the Constant but we can change its contents.

LOTTO = [ "a","b" ]; // Error
LOTTO.push(8); // No error

The key takeaway here is that a constant cannot be reassigned using the "=" operator. But we can change the contents of an Array or Object Constant.

A Sort of Homecoming

We instinctively understand what sort does.

But the behaviour of the JavaScript sort function may surprise some developers.

By default the sort function converts array elements into strings and orders the array based on Unicode values.

We attempt to sort this array of numbers

let sequence = [ 4,12,24,17,5,6,67 ];

But the result is ordered as strings.

// Result: [12, 17, 24, 4, 5, 6, 67]

The solution is to use a comparator function that works on adjacent pairs of values. This example uses an anonymous arrow function.

sequence.sort((a,b) => a-b);
// Result: [4, 5, 6, 12, 17, 24, 67]

This Mozilla help page gives more detailed coverage on the logic of comparator functions and sort.

10 things you're doing wrong with JavaScript


Possibly the biggest source of bugs in JavaScript arises from not understanding the ideas of copy by reference and copy by value.

When you make a copy of a string or number variable this will create a separate independent variable known as copy-by-value.

 let total = 10;
 let result = total;
 // total equals 10, result equals 11.

When making a copy of an array or object you need to be intentional in your code. This simple assignment will create two pointers to the same object known as copy by reference.

 let movie = { name:"North By NorthWest" };
 let film = movie;
 film.name = "Jaws";
 // Both film and movie contain { name:"Jaws" }

The JavaScript ES6 destructuring operator provides an elegant solution. This code breaks an object down into its component properties and then wraps them in a new object


We can refactor the previous code to create two separate objects.

 let movie = { name:"North By NorthWest" };
 let film = {...movie, name:"Jaws" ];

We can apply the same destructuring techniques to arrays 

 let lottery = [4,5,6,7,8];
 let lotto = [...lottery];

The Power of Equality

In JavaScript every object is unique. One consequence is that we need to think carefully about object comparison. These two objects contain the same contents but can never be the same. Comparison needs to happen at the property level.

 let italy = { capital:"Rome" };
 let italia = { capital:"Rome" };
 italy === italia; // false
 italy.capital === italia.capital; // true

Object comparison will always fail even if the objects are empty.

 {} === {}; // false

Once we understand that objects are unique, we also need to recognise the situation where object comparison returns a true value..

 let italy = { capital:"Rome" };
 let italia = italy; 

This code is an example of copy by reference. Both variables (italy, italia) are pointers to the same object. In this case object comparison will return true. We are comparing the SAME object. 

 italia === italy; // true
10 things you're doing wrong with JavaScript

Once Around the Block

Scope can be a big stumbling block in JavaScript. You might reasonably assume the scope of variable j to be defined by the for-loop that contains it.

for ( var j=0; j<10; j++ ) {
// Variable j still exists here.

But variables defined with the var keyword do not have block scope. Variable j continues to exist after the for-loop. To confuse matters further, variables defined with var are hoisted and come into existence at the start of their containing scope. You can solve both the block scope and hoisting problems with one word. Use keyword LET instead of VAR to define variables. It has block-scope and does not hoist.

This Is Your Life

The scope rules surrounding the keyword this in JavaScript are very complex. If you encounter bugs, the presence of keyword this should raise a red flag. Gaining an understanding of how this behaves is a key step on your learning path as a JavaScript developer. In this example we define an ES6 class.

class Movie {
      this.film = f;

We instantiate an object from the class and call the about method. Everything works. The name of the movie appears in the console.

const taxi = new Movie("Taxi Driver");

If we modify the method call and invoke the method differently things go wrong. This code calls the about method after a one second delay.

10 things you're doing wrong with JavaScript

But in the console undefined is displayed, not the name of the film.

The setTimeout function has changed the runtime value of this inside the about method so that it points to the global namespace (named Window in JavaScript.)

To solve this obscure problem, we can refactor the about method. JavaScript has been intentionally designed so that class methods which are written using arrow syntax will lexically bind the value of this correctly to the containing class.

about = () => console.log(this.film);

The about method will now work correctly in both these calls:

10 things you're doing wrong with JavaScript

Of all the topics covered in this article working with keyword this is clearly the most challenging.

Editor's note - you may notice some of this code is screenshotted - it was breaking our CMS!

Sonic Reducer

Reduce is a functional programming method which applies a function to every element of an array and reduces that array to a single value.

The custom reducer function that you write works on pairs of values and takes two arguments. This example finds the larger of two numbers.

const larger = (a,b) => Math.max(a,b)

We apply this function to an array using reduce to find the largest item.

const sequence = [ 2,12,4,6,41,10,8 ];
const largest = sequence.reduce( larger );

This code works but we need to handle the edge case where the array is empty. The code below will throw a runtime error.

sequence = [];
largest = sequence.reduce( larger );

This problem can occur when we define an empty array and then populate it with data returned from an asynchronous AJAX call. If reduce is invoked before the AJAX call completes this error will occur. The solution is to pass a second argument with an initial value.

largest = sequence.reduce( larger,0 );

The largest variable will contain zero if the array is empty. No error is thrown.

Function At The Junction

Here is a simple arrow function that calculates the area of a room.

const calcArea = (width,length) => {
 area = width*length;
 return area;
calcArea(6,4); // returns 24

This code works but contains a serious bug. We never declare variable area using either const or let. JavaScript will create an implied global. We have created a variable named area with global scope.

window.area; // contains 24

One obvious solution is to always declare variables with let or const. A second useful tool is to enable JavaScript strict mode. This will eliminate this silent error. A run-time error will be thrown when the function is called.

'use strict';
10 things you're doing wrong with JavaScript


Modern browsers include the Fetch API which enables you to make AJAX requests for JSON data from your JavaScript code.

We pass Fetch a path and it returns a Promise which we handle using a then method.

.then( data => console.log(data));

However this code does not log the data. Instead it displays an HTTP response object describing the outcome of this call. We need to add a second step using a json() method to extract data from the HTTP response. This requires chaining a second then method to get at the actual data.

.then(response => response.json())
.then(data => console.log(data));

Note this simple code does not include any error-handling. And additional work would be required if we were attempting an HTTP POST.

10 things you're doing wrong with JavaScript

My Life Is In Storage

LocalStorage provides a way to persist data across browser sessions. This can be useful when creating a prototype before "real data" is available.

This code stores and retrieves a name to/from localStorage.

 localStorage.capital = "Rome";

But attempting to store an object like this fails.

 const city = {name:"Pisa",region:"Tuscany"};
 localStorage.city = city;
 // Displays "[object Object]"

LocalStorage works with strings not JavaScript objects. We need to "stringify" data that we add and parse data that we retrieve.

 const city = {name:"Pisa",region:"Tuscany"};
 localStorage.city = JSON.stringify(city);
 // Correctly displays the object.

We also need to handle the edge case that localStorage.city returns undefined.

We can refactor all these ideas into a pair of arrow functions that read and write data into localStorage.

 const read = () => 
 localStorage.ob ? JSON.parse( localStorage.ob ) : {};
 const write = (ob) => localStorage.ob = JSON.stringify( ob );

Learn more about JavaScript

If you found this article useful and interesting check out our range of instructor-led  JavaScript and JavaScript framework training courses

The songs

Share this post on:

We would love to hear from you

Get in touch

or call us on 020 3137 3920

Get in touch