---
title: ES6 Syntax
---

If you've used JavaScript for only a (relatively) small amount of time or don't have much experience with it, you might not be aware of what ES6 is and what beneficial features it includes. Since this is a guide primarily for Discord bots, we'll be using some discord.js code as an example of what you might have versus what you could do to benefit from ES6.

Here's the startup code we'll be using:

```js title="index.js" lineNumbers
const { Client, Events, GatewayIntentBits } = require('discord.js'); // [!code word:const]
const config = require('./config.json');

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

// [!code word:=>]
client.once(Events.ClientReady, () => {
	console.log('Ready!');
});

client.on(Events.InteractionCreate, (interaction) => {
	if (!interaction.isChatInputCommand()) return;

	const { commandName } = interaction;

	if (commandName === 'ping') {
		interaction.reply('Pong.');
	} else if (commandName === 'beep') {
		interaction.reply('Boop.');
	} else if (commandName === 'server') {
		interaction.reply('Guild name: ' + interaction.guild.name + '\nTotal members: ' + interaction.guild.memberCount);
	} else if (commandName === 'user-info') {
		interaction.reply('Your username: ' + interaction.user.username + '\nYour ID: ' + interaction.user.id);
	}
});

client.login(config.token);
```

If you haven't noticed, this piece of code is already using a bit of ES6 here! The `const` keyword and arrow function declaration (`() => ...`) is ES6 syntax, and we recommend using it whenever possible.

As for the code above, there are a few places where things can be done better. Let's look at them.

## Template literals

If you check the code above, it's currently doing things like `'Guild name: ' + interaction.guild.name` and `'Your username: ' + interaction.user.username`, which is perfectly valid. It is a bit hard to read, though, and it's not too fun to constantly type out. Fortunately, there's a better alternative.

```js title="index.js" lineNumbers=19
} else if (commandName === 'server') {
	interaction.reply('Guild name: ' + interaction.guild.name + '\nTotal members: ' + interaction.guild.memberCount); // [!code --]
	interaction.reply(`Guild name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`); // [!code ++]
}
else if (commandName === 'user-info') {
	interaction.reply('Your username: ' + interaction.user.username + '\nYour ID: ' + interaction.user.id); // [!code --]
	interaction.reply(`Your username: ${interaction.user.username}\nYour ID: ${interaction.user.id}`); // [!code ++]
}
```

Easier to read and write! The best of both worlds.

### Template literals vs string concatenation

If you've used other programming languages, you might be familiar with the term "string interpolation". Template literals would be JavaScript's implementation of string interpolation. If you're familiar with the heredoc syntax, it's very much like that; it allows for string interpolation, as well as multiline strings.

The example below won't go too much into detail about it, but if you're interested in reading more, you can [read about them on MDN](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals).

```js
const username = 'Sanctuary';
const password = 'pleasedonthackme';

function letsPretendThisDoesSomething() {
	return 'Yay for sample data.';
}

console.log('Your username is: **' + username + '**.'); // [!code --:2]
console.log('Your password is: **' + password + '**.');
console.log(`Your username is: **${username}**.`); // [!code ++:2]
console.log(`Your password is: **${password}**.`);

console.log('1 + 1 = ' + (1 + 1)); // [!code --]
console.log(`1 + 1 = ${1 + 1}`); // [!code ++]

console.log("And here's a function call: " + letsPretendThisDoesSomething()); // [!code --]
console.log(`And here's a function call: ${letsPretendThisDoesSomething()}`); // [!code ++]

console.log('Putting strings on new lines\n' + 'can be a bit painful\n' + 'with string concatenation.'); // [!code --]
// [!code ++:5]
console.log(`
	Putting strings on new lines
	is a breeze
	with template literals!
`);
```

<Callout>
	As you will notice, template literals will also render the white space inside them, including the indentation! There
	are ways around this, which we will discuss in another section.
</Callout>

You can see how it makes things easier and more readable. In some cases, it can even make your code shorter! This one is something you'll want to take advantage of as much as possible.

## Arrow functions

Arrow functions are shorthand for regular functions, with the addition that they use a lexical `this` context inside of their own. If you don't know what the `this` keyword is referring to, don't worry about it; you'll learn more about it as you advance.

Here are some examples of ways you can benefit from arrow functions over regular functions:

```js
// [!code --:3]
client.once(Events.ClientReady, function () {
	console.log('Ready!');
});
client.once(Events.ClientReady, () => console.log('Ready!')); // [!code ++]

// [!code --:3]
client.on(Events.TypingStart, function (typing) {
	console.log(typing.user.tag + ' started typing in #' + typing.channel.name);
});
client.on(Events.TypingStart, (typing) => console.log(`${typing.user.tag} started typing in #${typing.channel.name}`)); // [!code ++]

// [!code --:3]
client.on(Events.MessageCreate, function (message) {
	console.log(message.author.tag + ' sent: ' + message.content);
});
client.on(Events.MessageCreate, (message) => console.log(`${message.author.tag} sent: ${message.content}`)); // [!code ++]

// [!code --:3]
var doubleAge = function (age) {
	return 'Your age doubled is: ' + age * 2;
};
const doubleAge = (age) => `Your age doubled is: ${age * 2}`; // [!code ++]

// [!code --:4]
var collectorFilter = function (m) {
	return m.content === 'I agree' && !m.author.bot;
};
var collector = message.createMessageCollector({ filter: collectorFilter, time: 15_000 });
const collectorFilter = (m) => m.content === 'I agree' && !m.author.bot; // [!code ++:2]
const collector = message.createMessageCollector({ filter: collectorFilter, time: 15_000 });
```

There are a few important things you should note here:

- The parentheses around function parameters are optional when you have only one parameter but are required otherwise. If you feel like this will confuse you, it may be a good idea to use parentheses.
- You can cleanly put what you need on a single line without curly braces.
- Omitting curly braces will make arrow functions use **implicit return**, but only if you have a single-line expression. The `doubleAge` and `filter` variables are a good example of this.
- Unlike the `function someFunc() { ... }` declaration, arrow functions cannot be used to create functions with such syntax. You can create a variable and give it an anonymous arrow function as the value, though (as seen with the `doubleAge` and `filter` variables).

We won't be covering the lexical `this` scope with arrow functions in here, but you can Google around if you're still curious. Again, if you aren't sure what `this` is or when you need it, reading about lexical `this` first may only confuse you.

## Destructuring

Destructuring is an easy way to extract items from an object or array. If you've never seen the syntax for it before, it can be a bit confusing, but it's straightforward to understand once explained!

### Object destructuring

Here's a common example where object destructuring would come in handy:

```js
const config = require('./config.json');
const prefix = config.prefix;
const token = config.token;
```

This code is a bit verbose and not the most fun to write out each time. Object destructuring simplifies this, making it easier to both read and write. Take a look:

```js
const config = require('./config.json'); // [!code --:3]
const prefix = config.prefix;
const token = config.token;
const { prefix, token } = require('./config.json'); // [!code ++]
```

Object destructuring takes those properties from the object and stores them in variables. If the property doesn't exist, it'll still create a variable but with the value of `undefined`. So instead of using `config.token` in your `client.login()` method, you'd simply use `token`. And since destructuring creates a variable for each item, you don't even need that `const prefix = config.prefix` line. Pretty cool!

Additionally, you could do this for your commands:

```js
client.on(Events.InteractionCreate, (interaction) => {
	const { commandName } = interaction;

	if (commandName === 'ping') {
		// ping command here...
	} else if (commandName === 'beep') {
		// beep command here...
	}
	// other commands here...
});
```

The code is shorter and looks cleaner, but it shouldn't be necessary if you follow along with the [command handler](../app-creation/handling-commands) part of the guide.

You can also rename variables when destructuring, if necessary. A good example is when you're extracting a property with a name already being used or conflicts with a reserved keyword. The syntax is as follows:

```js
// `default` is a reserved keyword
const { default: defaultValue } = someObject;

console.log(defaultValue);
// 'Some default value here'
```

### Array destructuring

Array destructuring syntax is very similar to object destructuring, except that you use brackets instead of curly braces. In addition, since you're using it on an array, you destructure the items in the same order the array is. Without array destructuring, this is how you'd extract items from an array:

```js
// assuming we're in a `profile` command and have an `args` variable
const name = args[0];
const age = args[1];
const location = args[2];
```

Like the first example with object destructuring, this is a bit verbose and not fun to write out. Array destructuring eases this pain.

```js
const name = args[0]; // [!code --:3]
const age = args[1];
const location = args[2];
const [name, age, location] = args; // [!code ++]
```

A single line of code that makes things much cleaner! In some cases, you may not even need all the array's items (e.g., when using `string.match(regex)`). Array destructuring still allows you to operate in the same sense.

```js
const [, username, id] = message.content.match(someRegex);
```

In this snippet, we use a comma without providing a name for the item in the array we don't need. You can also give it a placeholder name (`_match` or similar) if you prefer, of course; it's entirely preference at that point.

<Callout>
	The underscore `_` prefix is a convention for unused variables. Some lint rules will error or warn if you define
	identifiers without using them in your code but ignore identifiers starting with `_`.
</Callout>

## var, let, and const

Since there are many, many articles out there that can explain this part more in-depth, we'll only be giving you a TL;DR and an article link if you choose to read more about it.

1. The `var` keyword is what was (and can still be) used in JavaScript before `let` and `const` came to surface. There are many issues with `var`, though, such as it being function-scoped, hoisting related issues, and allowing redeclaration.
2. The `let` keyword is essentially the new `var`; it addresses many of the issues `var` has, but its most significant factor would be that it's block-scoped and disallows redeclaration (_not_ reassignment).
3. The `const` keyword is for giving variables a constant value that is unable to be reassigned. `const`, like `let`, is also block-scoped.

The general rule of thumb recommended by this guide is to use `const` wherever possible, `let` otherwise, and avoid using `var`. Here's a [helpful article](https://madhatted.com/2016/1/25/let-it-be) if you want to read more about this subject.
