Discord bot for ordering food I'm new to JavaScript, and I made a Discord bot using discord.js that serves food and drinks and replies without the need of a prefix. My issue is that I want to try cleaning up the code and get rid of all the if-statements, but I don't know how to do so.
bot.on(&quot;message&quot;, message =&gt; {
  const reply = [
    &quot;Here's your order!&quot;,
    &quot;Enjoy!&quot;,
    &quot;Here you go!&quot;,
    &quot;Let me know if you need anything else!&quot;,
    &quot;You've been served.&quot;,
    &quot;That'll be $3.50.&quot;,
    &quot;That'll be $5.50&quot;, 
  ];
  const response = reply[Math.floor(Math.random() * reply.length)];
  
  if (message.content.toLowerCase().includes(&quot;order coffee&quot;)) {
    message.channel.send(&quot;Coming right up!&quot;).then(msg =&gt; {
    msg.delete({ timeout: 5000 })
  })
  .catch(console.error);
    setTimeout(function(){
      message.reply(response);
      message.channel.send(&quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FCoffee%20cropped.gif?v=1613444146008&quot;);
    }, 5000);
  }  
  
  if (message.content.toLowerCase().includes(&quot;order latte&quot;)) {
    message.channel.send(&quot;Coming right up!&quot;).then(msg =&gt; {
    msg.delete({ timeout: 5000 })
  })
  .catch(console.error);
    setTimeout(function(){
      message.reply(response);
      message.channel.send(&quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FLatte.gif?v=1613444145762&quot;);
    }, 5000);
  }
  
  if (message.content.toLowerCase().includes(&quot;order muffin&quot;)) {
    message.channel.send(&quot;Coming right up!&quot;).then(msg =&gt; {
    msg.delete({ timeout: 5000 })
  })
  .catch(console.error);
    setTimeout(function(){
      message.reply(response);
      message.channel.send(&quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FMuffin.gif?v=1613444146225&quot;);
    }, 5000);
  }
  
  if (message.content.toLowerCase().includes(&quot;order strawberry cake roll&quot;)) {
    message.channel.send(&quot;Coming right up!&quot;).then(msg =&gt; {
    msg.delete({ timeout: 5000 })
  })
  .catch(console.error);
    setTimeout(function(){
      message.reply(response);
      message.channel.send(&quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FStrawberry%20cake%20roll.gif?v=1613444145762&quot;);
    }, 5000);
  }
});
The first thing to look at is: what is the same for each if statement and what is different. The key differences are:
message.content.toLowerCase().includes(&quot;this string here is what's different&quot;)

and
message.channel.send(&quot;links are different&quot;)

To clean it up, we can get rid of the if statements all together and create an object that contains key:value pairs with key message.content you want to check against with and value the associated media link. That would look like this:
const gifs = { 
  &quot;coffee&quot;: &quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FCoffee%20cropped.gif?v=1613444146008&quot;, 
  &quot;latte&quot;: &quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FLatte.gif?v=1613444145762&quot;,
  &quot;muffin&quot;: &quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FMuffin.gif?v=1613444146225&quot;,
  &quot;strawberry cake roll&quot;: &quot;https://cdn.glitch.com/1f3ad41e-6c0c-4160-902b-a50330e419bd%2FStrawberry%20cake%20roll.gif?v=1613444145762&quot;, 
};

We can take out the string &quot;order&quot; because that is also common to all of the keys. If the data you are getting back requires you to check on &quot;order coffee&quot; then change it back.
Now you can map through the keys of the gifs object to see if that key is included in the message content. If it is, return the value associated with that key.
Object.keys(gifs).forEach(key =&gt; { 
  if(message.content.toLowerCase().includes(key)) {
    return gifs[key]; // get the value at key in the gifs object
  }
}

Object.keys() takes an object and returns an array of the keys in that object. _.forEach is a method on an Array that loops through an array just like a for loop. It takes a callback function as a param.
Putting that all together we get:
// can define this in a helper / util file or at the top of this file since it is a constant list
const REPLIES_LIST = [
    &quot;Here's your order!&quot;,
    &quot;Enjoy!&quot;,
    &quot;Here you go!&quot;,
    &quot;Let me know if you need anything else!&quot;,
    &quot;You've been served.&quot;,
    &quot;That'll be $3.50.&quot;,
    &quot;That'll be $5.50&quot;, 
];

bot.on(&quot;message&quot;, message =&gt; { 
  const { channel, content, reply: messageReply} = message; // destructure variables off of message, reply: messageReply renames reply to messageReply
  const response = REPLIES_LIST[Math.floor(Math.random() * REPLIES_LIST.length)];

  Object.keys(gifs).map(key =&gt; { 
   if(content.toLowerCase().includes(key)) {
    channel.send(&quot;Coming right up!&quot;).then(msg =&gt; {
      msg.delete({ timeout: 5000 })
    }).catch(console.error);

     setTimeout(() =&gt; {
      messageReply(response);
      channel.send(gifs[key]); // get the value at key in the gifs object
    }, 5000);
   }
  });
});


Code Walkthrough

The bot gets a message &quot;message&quot; we declare temporary variables equal to message.content, message.channel, and message.reply by destructuring
Create another variable equal to a random response from the reply list or array
Traverse through the keys in the gifs object using forEach
For each item in the gifs object we check to see if the message.content.toLowerCase() includes that key, if it does we send a message &quot;Coming right up!&quot; to the channel
Handle some logic and a catch after sending
Create a setTimeout that waits 5 seconds before replying with the response and channel.sending the gif url

Updated: 02/17/21
There were comments questioning the use of _.map over _.forEach or _.some. We should be using _.forEach in this case and I updated the original answer to reflect that. Below I highlighted the differences between the three and ultimately what works best for this scenario.
Array.prototype.map((item) =&gt; // do something)
A method that iterates through every element of an array and returns a new array resulting from the callback function you passed.
Example:
 const list = [1, 2, 3, 4, 5];
 const newList = list.map((item) =&gt; item + 2); // [1+2, 2+2, 3+2, 4+2, 5+2]

 console.log(list); // [1, 2, 3, 4, 5]
 console.log(newList); // [3, 4, 5, 6, 7]

We only use map if we are using the array that the map returns (in this example newList. In the original answer, we were using map without returning anything or using the returned array which is an anit-pattern.
Array.prototype.forEach((item) =&gt; // do something)
A method that iterates through an array and uses a callback to mutate the array, returning undefined.
Example:
 const list = [1, 2, 3, 4, 5];
 list.forEach((item, index, arr) =&gt; arr[index] = item + 2);
 
 console.log(list); //[3, 4, 5, 6, 7]

The forEach provides you with the current item (item), index of the current item in the array (index), and the original array (arr).
We use forEach when we want to use the callback passed to mutate the array without returning a new array. Key thing to note, you cannot exit a forEach without raising an exception.
Array.prototype.some((item) =&gt; // do something)
A method that checks if at least one element in the array &quot;passes&quot; the callback you provide, returning a boolean.
Example:
 const list = [1, 2, 3, 4, 5];
 list.some((item) =&gt; item === 2); // true, stops when it reads 2 in the array because it matches
 
 console.log(list); //[1, 2, 3, 4, 5]

For the question that was asked, forEach is most appropriate. You then have to contemplate, will my data have duplicates or not have anything at all and handle those conditions. If you will have duplicates, you may want to you the find method approach Daniël van den Berg suggests. find is similar to forEach and some. It looks for the first item that matches the condition and returns that item.