Functions

The phone store employee probably doesn’t carry around a calculator to figure out the taxes and final purchase amount. That’s a task she needs to define once and reuse over and over again. Odds are, the company has a checkout register (computer, tablet, etc.) with those “functions” built in.

Similarly, your program will almost certainly want to break up the code’s tasks into reusable pieces, instead of repeatedly repeating yourself repetitiously (pun intended!). The way to do this is to define a function.

A function is generally a named section of code that can be “called” by name, and the code inside it will be run each time. Consider:

  1. function printAmount() {
  2. console.log( amount.toFixed( 2 ) );
  3. }
  4. var amount = 99.99;
  5. printAmount(); // "99.99"
  6. amount = amount * 2;
  7. printAmount(); // "199.98"

Functions can optionally take arguments (aka parameters) — values you pass in. And they can also optionally return a value back.

  1. function printAmount(amt) {
  2. console.log( amt.toFixed( 2 ) );
  3. }
  4. function formatAmount() {
  5. return "$" + amount.toFixed( 2 );
  6. }
  7. var amount = 99.99;
  8. printAmount( amount * 2 ); // "199.98"
  9. amount = formatAmount();
  10. console.log( amount ); // "$99.99"

The function printAmount(..) takes a parameter that we call amt. The function formatAmount() returns a value. Of course, you can also combine those two techniques in the same function.

Functions are often used for code that you plan to call multiple times, but they can also be useful just to organize related bits of code into named collections, even if you only plan to call them once.

Consider:

  1. const TAX_RATE = 0.08;
  2. function calculateFinalPurchaseAmount(amt) {
  3. // calculate the new amount with the tax
  4. amt = amt + (amt * TAX_RATE);
  5. // return the new amount
  6. return amt;
  7. }
  8. var amount = 99.99;
  9. amount = calculateFinalPurchaseAmount( amount );
  10. console.log( amount.toFixed( 2 ) ); // "107.99"

Although calculateFinalPurchaseAmount(..) is only called once, organizing its behavior into a separate named function makes the code that uses its logic (the amount = calculateFinal... statement) cleaner. If the function had more statements in it, the benefits would be even more pronounced.

Scope

If you ask the phone store employee for a phone model that her store doesn’t carry, she will not be able to sell you the phone you want. She only has access to the phones in her store’s inventory. You’ll have to try another store to see if you can find the phone you’re looking for.

Programming has a term for this concept: scope (technically called lexical scope). In JavaScript, each function gets its own scope. Scope is basically a collection of variables as well as the rules for how those variables are accessed by name. Only code inside that function can access that function’s scoped variables.

A variable name has to be unique within the same scope — there can’t be two different a variables sitting right next to each other. But the same variable name a could appear in different scopes.

  1. function one() {
  2. // this `a` only belongs to the `one()` function
  3. var a = 1;
  4. console.log( a );
  5. }
  6. function two() {
  7. // this `a` only belongs to the `two()` function
  8. var a = 2;
  9. console.log( a );
  10. }
  11. one(); // 1
  12. two(); // 2

Also, a scope can be nested inside another scope, just like if a clown at a birthday party blows up one balloon inside another balloon. If one scope is nested inside another, code inside the innermost scope can access variables from either scope.

Consider:

  1. function outer() {
  2. var a = 1;
  3. function inner() {
  4. var b = 2;
  5. // we can access both `a` and `b` here
  6. console.log( a + b ); // 3
  7. }
  8. inner();
  9. // we can only access `a` here
  10. console.log( a ); // 1
  11. }
  12. outer();

Lexical scope rules say that code in one scope can access variables of either that scope or any scope outside of it.

So, code inside the inner() function has access to both variables a and b, but code in outer() has access only to a — it cannot access b because that variable is only inside inner().

Recall this code snippet from earlier:

  1. const TAX_RATE = 0.08;
  2. function calculateFinalPurchaseAmount(amt) {
  3. // calculate the new amount with the tax
  4. amt = amt + (amt * TAX_RATE);
  5. // return the new amount
  6. return amt;
  7. }

The TAX_RATE constant (variable) is accessible from inside the calculateFinalPurchaseAmount(..) function, even though we didn’t pass it in, because of lexical scope.

Note: For more information about lexical scope, see the first three chapters of the Scope & Closures title of this series.