Vital Concepts for Modern JS Developers

Still the de facto language of the web, JavaScript has a long and fragmented history. Key players have made concerted efforts in recent years to have JavaScript conform to a standard known as ECMA-262 or ECMAScript.

Coming into 2019, major milestones like ECMAScript 2015 (ES2015, formerly ES6) are still not completely implemented by any front- or back-end JavaScript engines.

Since ES2015, the standards group has decided to release specifications once a year, and ES2016, ES2017, ES2018, and ES2019 all add interesting features. But it can be tough to keep on top of what’s useable and useful in JavaScript right now—whether it’s cutting-edge magic or tried-and-true techniques.

Hence this community-driven project, bringing together expert advice on the most important advanced concepts that modern JS developers should know. We welcome your contributions and feedback.

Closures and Higher-order Functions

Closures and higher-order functions are two important concepts in JavaScript, and ones that are closely related. Let’s find out how.

Closures

When we create a function inside another function in JavaScript, the inner function has access to the scope of the outer function as well as its own.

In the code example below, the count function is able to access total, which is defined in the outer scope within tallyCounter.

function tallyCounter() {
  let total = 0;

  function count() {
    total++;
    return total;
  }
}

Here, the count function is a closure, and continues to have access to the total variable even after tallyCounter has finished executing. This is due to lexical scoping in JavaScript, allowing functions to access variables even when they’re called from outside of the scope in which they were initially created.

The above code isn’t very useful, though, because we can’t call count from the outside. It was defined in the tallyCounter scope, and it’s not available to the outside:

function tallyCounter() {
  let total = 0;

  function count() {
    total++;
    return total;
  }
}

console.log(count()); // Error: count is not defined

In order for our closure to become useful, we need to return it. That way, we can assign it to a local variable outside of tallyCounter, and start using it:

function tallyCounter() {
  let total = 0;

  return function count() {
    total++;
    return total;
  }
}

let count = tallyCounter();

console.log(count()); // log: 1
console.log(count()); // log: 2
console.log(count()); // log: 3

In the example above, we don’t have access to the total variable from outside of the tallyCounter function. We’re able to call count and increment total from the outside but we cannot access the value directly. As such, closures are often used in JavaScript to protect variables from outside manipulation, or to hide implementation details.

Another common use case for closures is deferring code execution. Callbacks in JavaScript are a prime example of this:

function logTheDateLater(delay) {
  let date = new Date();

  function logDate() {
    console.log(date);
  }
  
  setTimeout(logDate, delay);
}

Here, we’re calling setTimeout with a callback function that will output the current date and time—as of calling the outer function—but after some delay. Internally, setTimeout will call our callback function after the delay, without any knowledge of what it does or how it works. It also does not have access to the date variable. Because our callback function is a closure, it has access to date in its lexical scope, and it can log it to our console.

Higher-order Functions

Both tallyCounter and setTimeout are what we call higher-order functions in JavaScript. These are functions that either return another function, or accept one or more function(s) as input parameters.

They are called higher-order because they are more concerned with higher-level concepts than lower-level details. As we mentioned before, callbacks are a great example of that:

function helloToptal() {
  console.log('Hello Totpal');
}

setTimeout(helloToptal, 1000);

Here, setTimeout is a higher-order function because it accepts a callback function, and will execute it after a given delay. It does not need to know what that JavaScript function does.

Now, let’s say we want to make sure that we don’t log "Hello Toptal" more than once per second. Here’s a higher order function that will help us achieve that:

function throttle(fn, milliseconds) {
  let lastCallTime;

  return function() {
    let nowTime = Date.now();

    if(!lastCallTime || lastCallTime < nowTime - milliseconds) {
      lastCallTime = nowTime;
      fn();
    }
  };
}

The throttle function accepts a function parameter, and returns a new, throttled function to the caller. We can now use it to create a throttled version of our helloToptal function:

let helloToptalThrottled = throttle(helloToptal, 1000);
setInterval(helloToptalThrottled, 10);

You’ll notice that, despite the 10ms interval, calls to helloToptal are throttled and "Hello Totpal" will only be logged once per second.

Higher-order functions like throttle allow us to compose our JavaScript applications from smaller, single-responsibility units of code that are easier to test, reusable, and certainly a lot more maintainable.

Contributors

Merott Movahedi
Merott Movahedi

JavaScript Developer @ Toptal

Merott is a full-stack developer with a strong interest in the front-end space. He is proficient in JavaScript and has a good grasp of its core concepts and best practices. He is also strong in JavaScript frameworks, especially Angular. In addition to web development, he has an interest in mobile apps, on which he spends a substantial amount of time. Merott absolutely loves to use his programming skills to automate and streamline mundane tasks.

Like what you're reading?Get the latest updates first.

Thank you for subscribing! Check your inbox to confirm subscription. You’ll start receiving posts after you confirm.

Template Strings

ES6 adds a new feature called “template strings.” At first glance, they may look similar to string interpolation in other languages such as Ruby and PHP. Yes, they can be used to implement the same behavior:

const name = 'David'
const myStr = `Hello, ${name}!`
console.log(myStr)

This logs Hello, David! to the console. Anything between ${ ... } is interpolated into the string.

But in reality, template strings are a lot more powerful than that. Behold:

const name = 'David'

// Template string functions take the first argument as
// an array of strings which are the pieces of the template string
// and a variadic amount of arguments following that representing
// the inserted tokens at each position
const escape = (parts, ...tokens) => {
    let result = ''

    // iterate the parts array
    for (let i = 0; i < parts.length; i++) {
        result += parts[i]

        // if we haven't reached the end of the parts array... 
        if (i < parts.length - 1) {
            // ... Surround the token with quotes
            result += '"' + tokens[i] + '"'        
        }
    }

    return result
}

const myStrAutoQuoted = escape`Hello, ${name}!`
console.log(myStrAutoQuoted)

This will log Hello, "David"! to the console. The syntax here is important; see how we simply put the name of the template function right before the template string without parentheses. Note how the variable name was automatically quoted! This is just the beginning of how powerful template strings really are. They add another dimension to the possibilities of JavaScript programming.

This feature is used in many new JavaScript libraries, including styled-components, which allows developers to write CSS in JS in a very clean way:

import styled from 'styled-components'
import { render } from 'react-dom'

const RedSquare = styled.div`
    width: ${props => props.size}px;
    height: ${props => props.size}px;
    background-color: red;
`

render(<RedSquare size={20} />, document.getElementById('container'))

This will render a red square box of size 20 pixels on the screen.

Contributors

David Xu
David Xu

JavaScript Developer @ Toptal

David has taken several mobile apps from an idea to millions of users all over the world, as the Chief Architect of Castle Global, Inc and technical lead in other companies. He has been programming since the age 9 and has won medals in various competitive programming competitions, from the Australian Informatics Olympiad to ACM-ICPC. David has invaluable experience in all areas technical, from architecture and design to engineering and DevOps.

Like what you're reading?Get the latest updates first.

Thank you for subscribing! Check your inbox to confirm subscription. You’ll start receiving posts after you confirm.

The Rest and Spread Operators

ES6 adds new syntax for doing rest and spread, but the operator looks like ... in both cases. Rest was already doable before ES6, but it required a lot more code. It also didn’t look as pretty.

To illustrate this, let’s write a function called getUser that takes an object containing either a userId or username property, in ES5:

function omit() {
    if (arguments.length < 2) {
        throw new Error('omit requires at least 2 arguments')
    }

    var obj = arguments[0],
        keys = Array.prototype.slice.call(arguments, 1)

    var ret = {}

    for (var key in obj) {
        if (obj.hasOwnProperty(key) && keys.indexOf(key) === -1) {
            ret[key] = obj[key]
        }
    }

    return ret
}

function getUser(params) {
    var userId = params.userId,
        username = params.username,
        args = omit(params, 'userId', 'username')
    
    if (typeof userId !== 'undefined') {
        return getUserById(userId, args)
    }

    if (typeof username !== 'undefined') {
        return getUserByUsername(username, args)
    }

    throw new Error('either userId or username needs to be passed')
}

Note that we had to write our own omit function to not include certain keys. We also had to duplicate the userId and username fields, once in the var definition and once in our call to omit. Let’s take a look at the same code written using the ES6 rest operator:

function getUser(params) {
    const { userId, username, ...args } = params
    
    if (typeof userId !== 'undefined') {
        return getUserById(userId, args)
    }

    if (typeof username !== 'undefined') {
        return getUserByUsername(username, args)
    }

    throw new Error('either userId or username needs to be passed')
}

As you can see, this is much easier to read and understand what is going on at a first glance, and there was no need for the extra omit helper function.


The ES6 spread operator is also very helpful. For example, it can be used to spread multiple sources into a destination:

function mergeThreeObjects(obj1, obj2, obj3) {
    return { ...obj1, ...obj2, ...obj3 }
}

console.log(mergeThreeObjects({ x: 1 }, { y: 1 }, { y: 2, z: 3 })

This logs { x: 1, y: 2, z: 3 }. Note that later keys will overwrite earlier keys, much like Object.assign() in ES5. (See how the y property in the third argument overwrote the y property in the second argument.)

There is also syntax to do the reverse:

function addEmailToUser(email, user) {
    return { email, ...user }
}

Here, this addEmailToUser function copies the top-level attributes of user to an object that has only the email property. Note that this is a shallow copy. The equivalent code in ES5 is:

function addEmailToUser(email, user) {
    return Object.assign({ email: email }, user)
}

The ES6 rest/spread operators also work with arrays, which can make older syntax such as that using Array.prototype.concat and Array.prototype.slice a lot more readable:

ES5:

var list = [0, 1, 2, 3, 4, 5, 6]
var first = list[0]
var rest = list.slice(1)
console.log(first, rest)

ES6:

const [ first, ...rest ] = [0, 1, 2, 3, 4, 5, 6]
console.log(first, rest)

These both log 0, [1, 2, 3, 4, 5, 6].

The spread operator with arrays can also replace the old ES5 way of using Array.concat to combine arrays:

ES5:

var others = [1, 2, 3, 4]
var arr = [1, 2].concat(others)

ES6:

const others = [1, 2, 3, 4]
const arr = [1, 2, ...others] // [1, 2, 1, 2, 3, 4]

As you can see, ES6’s rest and spread operators sometimes just provide syntactic sugar, but other times are much more powerful than that. Enjoy!

Contributors

David Xu
David Xu

JavaScript Developer @ Toptal

David has taken several mobile apps from an idea to millions of users all over the world, as the Chief Architect of Castle Global, Inc and technical lead in other companies. He has been programming since the age 9 and has won medals in various competitive programming competitions, from the Australian Informatics Olympiad to ACM-ICPC. David has invaluable experience in all areas technical, from architecture and design to engineering and DevOps.

Like what you're reading?Get the latest updates first.

Thank you for subscribing! Check your inbox to confirm subscription. You’ll start receiving posts after you confirm.

Understanding Async/Await

Understanding asynchronous programming is essential to modern software development and the creation of progressive web applications. Without a good understanding of how it works, it can be very easy to write code that turns into an unmanageable mess, especially as client expectations grow and change throughout the course of a project.

Functionality changes can also demand that code be converted from synchronous to asynchronous. These are equally important in server-side code and client-side code.

Thankfully, in recent years, JavaScript has greatly simplified the process, especially with the availability of async and await.

Overview of Promises

JavaScript promises are simply a way of attaching callback functions to some asynchronous event, such as a call to fetch records from a database. Since the database server won’t necessarily respond immediately, we would need to attach a callback to wait for the response rather than block the rest of our application from continuing.

Promises allow us to chain events together recursively or iteratively and to use the resulting data at each step. It’s a very powerful tool, but without a defining structure, code can look very unreadable pretty quickly. The example given below reads employee records from a database and then dumps them to the console:

db.manyOrNone ('select * from employee')
.then (console.log); 

The first line issues the call to the database and returns a Promise, which can be thought of as a thread with two callback functions attached, resolve and reject—although it doesn’t necessarily have to be implemented internally using threads. The code in this thread will continue to run without blocking any other part of our code, and when it’s done, the resolve function will be called, passing any resulting data to it. If any error is encountered, the reject function will be called instead, with an error code being passed to it.

In the second line of code, we’re calling the .then() method on the returned Promise object, which attaches the handler for the resolve part of our promise. In this case, we’re just attaching console.log as the handler, which will output the returned data to the console. But inside our callback function, we can do whatever we want with the data, knowing that it will be called only when the database fetch has been completed.

Developers familiar with jQuery are used to this same type of pattern, although in that case, a callback function is usually passed as a parameter or a member of a settings object.

This code is very simple and readable, but as we’ll see in the next section, things can easily get pretty messy.

The Problem

There are certain cases where writing promise-based code can be quite complicated. One of them is promises that are based on conditions. Let’s say we have an employee object, and we want to query information about their medical coverage, but only if they’re employed full-time. We might write code like this:

getMedicalCoverage(employee)
.then (console.log);

function getMedicalCoverage(employee) {
   if (!employee.isFullTime) {
      return (Promise.resolve (null));
   }
   else {
      return (db.manyOrNone ('select * from coverage where employee_id=' + employee.id));
   }
}

In this example, the getMedicalCoverage function will return a Promise whether the employee is full-time or not. If the employee isn’t full-time, it returns a Promise that gets resolved immediately with a value of null. If they are full-time, it performs a database query that gets resolved after the data is fetched.

Data fetching that is based on a condition typically requires us to create a promise either way, and that’s code we have to write every single time we encounter this scenario. These code patterns can be made much simpler to manage by using async and await, so let’s start with a description of how it works.

Async/Await to the Rescue

In modern JavaScript, async and await are used to handle this process in a much more concise way. First, let’s start by building an understanding of what async does. When we write a function that is intended to run without blocking the rest of our code and/or interface, we’d define it as an async function, using the following syntax:

async function readEmployees () {
   var employees = ["Elsa", "Anna", "Kristoff"];
   return (employees);
}

And here’s the syntax in case we’re using ES6 arrow functions:

const readEmployees = async () => {
   var employees = ["Elsa", "Anna", "Kristoff"];
   return (employees);
};

Never mind the fact that this function is simply returning an array of predefined strings for now. The point is that we’ve defined it as an asynchronous function, which means that JavaScript automatically wraps it in a Promise. This causes a Promise to be created, with this function as the body of that Promise. When we return a value from the function, it acts as a resolve for the Promise.

Now, let’s look at an example of how to call an asynchronous function:

var employees = await readEmployees ();

It’s really that simple! We just insert the await keyword before the function call itself. No matter what goes on under the hood (API calls, database calls, etc.), the calling environment doesn’t need to be concerned with anything but calling the function and using the return value.

Keep in mind that we can’t use await unless it’s inside an asynchronous function. Defining a function as async exposes the await keyword inside its scope. The idea is that our top-level function that kicks off a whole process needs to be treated as a regular promise that has a .then() handler waiting for it to finish, but the internal steps can be blocking. Here’s an example that demonstrates the whole process:

const readEmployees = async () => {
   var employees = await db.manyOrNone ('select * from employee');
   for (let i=0; i<employees.length; i++) {
      employees[i].dept = await db.oneOrNone ('select * from dept where id=' + employees[i].deptId);
   }
   return (employees);
}

readEmployees()
.then (console.log);

In the global scope here, we’re calling readEmployees() and attaching a .then() handler which outputs the employee list to the console. Inside readEmployees(), we’re doing a series of database calls, and the number of calls depends on the data we receive.

First, we await on a call to retrieve the employee list. Then for each employee in that list, we want to assign a field that describes the department they belong to, so once again, we await on a call to the database to get that information. Finally, we return the modified employee list and that’s what gets resolved from the promise.

Of course, we could’ve replaced the loop with an SQL join. The point is that the assignment statement is one line of code and looks as straightforward as if it were a simple synchronous call, which demonstrates the beauty of using async and await.

Returning to our previous example where we queried medical coverage for an employee based on the condition of them being employed full-time, let’s see how it would be tackled using async and await:

getMedicalCoverage(employee)
.then (console.log);

async function getMedicalCoverage(employee) {
   return (!employee.isFullTime ? null
     : await db.manyOrNone ('select * from coverage where employee_id=' + employee.id));
}

The call to getMedicalCoverage is the same, and expects a Promise, and uses .then() to handle processing the result. But the function itself is much simpler. It checks the condition and either returns null, or awaits on another promise, which is the call to the database.

Incorporating loops into promises can also be complicated. If we want to run some asynchronous code on each element of an array, a typical approach is to write a recursive function that creates a promise for the first element, and when that promise is resolved, the function recursively calls itself for the next element, until it’s done.

There’s a lot of overhead with implementing it this way, but it’s much more concise when we use async/await:

async function getAllPaystubs(employee) {
   for (let i=0; i<employee.payments.length; i++) {
      employee.payments[i].paystub = await getPaystub(employee.payments[i].id);
   }
}

Much simpler and way easier to maintain.

You might be wondering, what if we want our promise in an async function to be rejected? We may have a database call that fails because of a lost connection, and so the corresponding promise needs to be rejected. Without a reject function to call, what do we do? The answer is, we throw an exception. So our code would look something like this:

async function readEmployeesFromDept (deptID) {
   if (isNaN (deptID) {
      throw "Invalid department ID";
   }
   else {
      return (await db.manyOrNone ('select * from employee where deptID=' + deptID));
   }
}
readEmployeesFromDept(deptID)
.catch (console.log);

Introducing asynchronous logic can quickly lead to spaghetti code. Hopefully, this explanation of using async and await to manage it all will help you to write cleaner, more concise, and more manageable asynchronous code.

Contributors

Eric Adem
Eric Adem

JavaScript Developer @ Toptal

Eric is a senior software developer who's driven by results, quality, and efficiency. He can leverage his extensive experience to help develop your product within large corporate or startup environments. He truly understands client and end-user needs, and he designs solutions that are cost-effective, flexible, and scalable.

Like what you're reading?Get the latest updates first.

Thank you for subscribing! Check your inbox to confirm subscription. You’ll start receiving posts after you confirm.

Using Binary and Ternary Operators to Increase Readability and Reduce Your Code

There are many developers who have a year or two of experience and ask themselves the following: How do I become a better developer? How do I go from being a middle- or beginner-level developer to the next level? The key is experience, but what is important about it is not time but what do you do in that time. Valuable experience is all about the knowledge you have and how well you apply it. This means you can hack the amount of experience by learning and putting into practice as many ideas as possible.

In this article you’ll learn some tricks that are not common for developers to learn. But most importantly, you’ll learn how to apply these tricks to real-world examples. This will help you grow your skills faster.

Code Readability

A good coder shouldn’t limit themselves to only writing code that works; they should write code that can stand the test of time. As you grow as a developer, you start to realize that, often, you won’t be there for any changes the code will need. The reasons are many, like switching jobs, or simply having to focus on other features while another coder works on your previous code. That’s why writing clear code becomes as important as the functionality of it.

You may have written a piece of code five years ago, and even to yourself now it seems it was written by an stranger. So it would be irresponsible to write code that sacrifices readability just for the sake of proving you know some weird hack of the language.

The tricks you’re about to learn are going to compress the code you’re writing under some circumstances; however, you shouldn’t abuse these tricks. Increasing readability is the actual objective of these tricks, as I’ll help you express the same ideas with less lines. Writing less code results in code that is more manageable, which you’ll appreciate as you jump to more complex and bigger codebases.

Overview

Because I want to focus on some weird but practical tricks, we’ll be looking at these operators:

  • && (the and operator)
  • || (the or operator)
  • % (the mod operator)
  • ? : (the ternary operators)

The And Operator

This operator might not be a stranger—you might have used it in the past to verify that multiple conditions are met. Like the following example:

if (bankAccount.amount > item.price && item.inventory >= shippingItem.qty) {
  buy();
}

But when we use the && operator, the result isn’t necessarily true or false—it’s actually the value of the last condition that has been met. So we get a true value only in the case that all conditions are be considered truthy. Truthy is easier to define as the opposite of what is falsy. Falsy is a value treated as false for JavaScript, and that includes the following values:

  • null
  • undefined
  • false
  • 0
  • ""
  • NaN

This will give you an idea of how this works:

// 3 and 5 are not falsy so both conditions are truthy
3 && 5 // result: 5

This might look like a very useless thing to know; however, this is very powerful when you want to check if a value exists under an object which itself might or might not exist.

Let’s say you’re creating a component which has a config object in which you might set a style object to set the fontSize. And let’s make the default fontSize 14 in case it isn’t set on the config object.

The code to do that might look like the following:

var config = {
  style: {
    fontSize: 12
  }
};
var fontSize = 14;

if (config.style) {
  if (config.style.fontSize) {
    fontSize = config.style.fontSize;
  }
}

After applying the && operator and the || operator (which you’ll learn next) it reduces to:

var config = {
  style: {
    fontSize: 12
  }
};
var fontSize = (config.style && config.style.fontSize) || 14;

Another powerful trick of this operator is that the second condition will only be executed if the first condition is truthy.

In our next example, let’s imagine your form component may have a callback function when it’s submitted, but this callback may or not exist. To call it, you might do the following:

if (this.onSubmit) {
  this.onSubmit();
}

However, with the && operator, this gets reduced to:

this.onSubmit && this.onSubmit();

You don’t care about the result, you just care that the function gets executed in the case where it exists.

The Or Operator

Again, you might have used it under conditional statements, but also again, this operator can return something different from true or false. It returns the first truthy part.

// 24 and 45 are both truthy
24 || 45 // returns 24

This is very helpful to set default values on the code, but please note that this only works if a falsy value isn’t valid input. Let’s say we are working on a food platform and want to know how many ice cream cones a client wants. However, the default will be 1. Using this operator, you’ll have the following:

var qty = order.ice_cream || 1;

So if the client orders one or more ice cream cones, the result will be correct. But if the client selects zero, the result will be one—please beware of this! In the case we explored before—about fontSize—it works perfectly since zero isn’t expected as valid input.

This || operator combined with the && operator can verify the existence of an object, get the value, and in the case of non-existence, default to a predefined value.

The Conditional (Ternary) Operator ?:

Have you ever written an if statement whose only purpose was to set a value on a variable depending if a condition is met? Let’s say, for example, you want to change the background color of a page depending on whether the user has a premium subscription. Your code might look like this:

if (user.premium){
	this.headerBar.style.backgroundColor = colors.GOLD;
} else {
this.headerBar.style.backgroundColor = colors.BLUE;
}

There will be times when you’re facing this situation. Fortunately, the ternary operator can help you express the same thing in a more compact way. The operator has three parts:

  1. The condition
  2. Code that is returned if the condition is met
  3. Code that is returned if the condition is not met

So:

if (a) {
  b;
} else {
  c;
}

Will transform into:

a ? b : c

Back to our previous example using the ternary operator, the code can be rewritten as:

this.headerBar.style.backgroundColor = user.premium ? Colors.GOLD : Colors.BLUE;

Another use is formatting text depending on certain conditions, like if we have a price and we want to display it as a dollar amount or cents:

var priceText = (price < 1) ? ("$" + price.toFixed(2)) : (price * 100 + "¢");

The % Operator

This one is a very strange operator, as it returns the remainder of a division operation. Let’s start by understanding how it works. Say you do 5 % 3: If you divide 5/3 the result is 1 if you don’t calculate any decimals; your remainder will be 2. Seems like it won’t have a lot of use until you start dealing with time.

Let’s say for example you’re building a stopwatch. If you search on the internet, you’ll see that most of the code out there tries to add the time that has passed by adding each second that has passed. This results in more complexity than needed.

We only need to know how much time has passed. Let’s say the current time is 150,678 ms, i.e., the time that’s passed since the stopwatch began to run. You’ll need to process that amount into minutes and seconds, which would be 02:30. If you want to display how many minutes and seconds have passed, you can do the following:

var seconds = (currentTime / 1000); // get the total number of seconds
seconds = (seconds | 0); // take away the decimal part

// this will divide by 60 which will be the minutes and
// the remainder is the number of leftover seconds
seconds = (seconds % 60); 

// using same approach to calculate minutes:
var minutes = ((currentTime / (60 * 1000)) | 0) % 60;

Another use of the % operator is when dealing with next and previous functions that cycle when they reach the last item. Say you have a slideshow and the way you render a slide is by calling show(slideIndex), and you have an array with all the slides. Usually your next function will look like this:

function next() {
  if (this.currentIndex + 1 < this.slides.length) {
    this.show(this.currentIndex + 1);
  } else {
    this.show(0);
  }
}

Using the % operator, that will be:

function next(){
  this.show((this.currentIndex + 1) % this.slides.length);
}

Using All These Tricks Together

Using all that we have covered here, we can build a simple stopwatch with the following code in less than 30 lines of code:

function StopWatch(config){
  // create config object in case none was sent
  config = config || {}
  // Read fontsize from config or set default to 12
  var fontSize = (config.style && config.style.fontSize) || 12;
  // Read color from config or set default to #000
  var color = (config.style && config.style.color) || '#000';

  var element = document.createElement('div');
  // add the color and font size to the div 
  //  that will hold our stopwatch
  element.style.color = color;
  element.style.fontSize = fontSize;

  // Save when the stopwatch starts running
  var startTime = new Date().getTime();
  setInterval(function() {
    // Calculate how much time has passed since 
    // the stopwatch started running
    var currentTime = new Date().getTime() - startTime;
    var seconds = Math.floor(currentTime / 1000) % 60;
    var minutes = Math.floor(currentTime / (60 * 1000)) % 60;
    seconds = (seconds < 10 ? '0' : '') + seconds;
    minutes = (minutes < 10 ? '0' : '') + minutes;
    element.innerHTML = (minutes + ':' + seconds)
  }, 500);
  return element;
}
document.body.appendChild(new StopWatch())

As you can see, the tricks I’ve discussed here have made it possible to write the same meaning in less lines of code. Now imagine this code is part of a huge project. If you can view the entire code, even with comments, without needing to scroll, then it will be easier to understand and modify.

However, I never went short on variable names, nor made this look like minified JS, which will have happen if we start changing element to e, or seconds to s. Using those names for variables will make you stop for a moment and think, In this context, what is e or s?

If you doubt whether you should apply one of these conciseness techniques, ask yourself the following: By making things this way, the next time I come to the code and view it with the eyes of a stranger, will it be easier or harder to understand? Happy coding!

Contributors

Juan has over ten years of freelance UX experience. His projects span a wide variety but are all rooted in his commitment to always provide the best experience to the user. Juan has developed applications used by high-profile clients and so has learned to commit to perfection of detail in his work.

Submit a tip

Fields marked with an asterisk (*) are required

Thanks for submitting your tip proposal
Our editorial staff will review it shortly. Please note that tips proposals are subject to review and editing, and may or may not be selected for posting, at the sole discretion of Toptal, LLC.