Let's be friends

This is in the works! Would you like to help flesh it out? Let's do it!

No arguments

example.js
function greet() {
  console.log("Hello, welcome to the store!");
}

greet();  // logs: "Hello, welcome to the store!"

Even without any arguments, functions can encapsulate a useful reusable procedure. But without a way to include outside information, they can really only do that one exact thing.

Single argument (assuming it exists)

example.js
function addToCart(item) {
  console.log(`Added ${item} to the cart.`);
}

addToCart("Shoes");  // logs: "Added Shoes to the cart."

When you introduce an argument, the function starts becoming dynamic.

This function takes a single argument (item) and uses it to generate a message. But what if the argument is missing? Maybe your program can 100% fully count on it always being there. But maybe not?

Dealing with a missing or optional argument

example.js
function addToCart(item) {
  if (!item) {
    console.log("Error: No item provided.");
    return;
  }
  console.log(`Added ${item} to the cart.`);
}

addToCart("Shoes");  // logs: "Added Shoes to the cart."
addToCart();  // logs: "Error: No item provided."

If the argument is missing, we need a way to handle that.

This error prevention pattern checks if the argument is missing and provides a useful message.

It will clutter the function with many checks as more arguments are added. You’ll be using addToCard(item) though, and so this is just the definition of the function (not how you’ll use it).

example.js
function addToCart(item) {
  var item = item ?? "Generic item";  // Sets a default if item is null or undefined
  console.log(`Added ${item} to the cart.`);
}

addToCart("Shoes");  // logs: "Added Shoes to the cart."
addToCart();  // logs: "Added Generic item to the cart."

You could do a little check inside the function definition like this and see if the argument was passed in, and if not, set a default.

(You’ve probably seen this pattern while writing reusable PHP templates)

example.js
function addToCart(item = "Generic Item") {
  console.log(`Added ${item} to the cart.`);
}

addToCart("Shoes");  // logs: "Added Shoes to the cart."
addToCart();  // logs: "Added Generic Item to the cart."

Here’s the more modern way to set a default value if the argument is not provided.

This makes the function more flexible and avoids the need for extra checks.

But you can imagine if there were a lot of them, that it would get hard to read.

example.js
function addToCart(item) {
  if (typeof item !== 'object' || item === null) {
    console.log("Error: Invalid item. Expected an object.");
    return;
  }
  console.log("Added item:", item);
}

addToCart({ name: "Shoes", price: 49.99 });  // logs: Added item: { name: "Shoes", price: 49.99 }
addToCart("Shoes");  // logs: Error: Invalid item. Expected an object.
addToCart(true);  // logs: Error: Invalid item. Expected an object.

What if the argument is the wrong type? If you know your “item” is a specific object with id, name, price etc. – and someone accidentally just sends in true, what would happen?

The typeof keyword typeof is a quick way to check the type of item. We ensure it’s an object.

example.js
// some ways to check

if (!Array.isArray(cart)) {
  console.log("Error: Cart should be an array.");
  return;
}

if (typeof name !== 'string') {
  console.log("Error: Name should be a string.");
  return;
}

if (typeof isGift !== 'boolean') {
  console.log("Error: isGift should be a boolean.");
  return;
}

if (typeof price !== 'number') {
  console.log("Error: Price should be a number.");
  return;
}

//

function addToCart(item) {
  if (typeof item !== 'object' || item === null || !item.name || typeof item.name !== 'string' || typeof item.price !== 'number') {
    console.log("Error: Invalid item. Expected an object with 'name' (string) and 'price' (number).");
    return;
  }
  console.log(`Added ${item.name} priced at $${item.price} to the cart.`);
}

addToCart({ name: "Shoes", price: 49.99 });  // logs: Added Shoes priced at $49.99 to the cart.
addToCart({ name: "Shoes", price: "free" });  // logs: Error: Invalid item. Expected an object with 'name' (string) and 'price' (number).
addToCart("Shoes");  // logs: Error: Invalid item. Expected an object with 'name' (string) and 'price' (number).

Depending on how you design your functions… they might get really horrible and messy. So, design them nice and clean and simple!

x

example.js

x

Coming back to this…

  • Assuming the Argument Exists: Simple and direct, assumes arguments are always passed.
  • Basic Parameter Check with if Condition: Adds a layer of error prevention, checking for missing arguments.
  • Using Default Parameter Values: Provides a fallback when arguments are missing, simplifying code logic.
  • Accessing the arguments Object: Accesses all passed arguments without defining parameters.
  • Rest Parameters (...args): A modern way to capture all arguments, using an array.
  • Handling Edge Cases (Duck-typing): A practical method to handle unexpected input values like null, undefined, or empty strings.
  • Combining Default Values and Rest Parameters: Handles flexible arguments with defaults for certain parameters.
  • Throwing Errors for Missing or Invalid Arguments: Enforces strict argument requirements, ensuring your function is used correctly.

 

And we should also talk about “pure” functions and side-effects –

Let's be friends