This content originally appeared on Envato Tuts+ Tutorials and was authored by Alberta Williams
In our previous tutorial, we talked about loops in JavaScript. One of the tasks there required you to write a loop to calculate the factorial of a number. Let's say that you had to calculate the factorial of 10, and you wrote a for loop to do that. Then, someone asked you to calculate the factorial of 20 other numbers. It isn't practical for you to rewrite the same loop again and again to change just one value.
What if you could just write the loop once and make the number whose factorial you want to calculate a parameter that could be passed to the loop? This is exactly what functions do, and it saves a lot of time and code duplication.
A function is a group of statements that perform a specific task. Functions allow us to break up a program into smaller programs, making our code more readable, reusable, and testable.
Void Functions
There are two ways that the factorial function I mentioned above could work. One possibility is that it could directly output the calculated answer. In this case, it won't give us anything back that we could assign to some other variables. It will simply output the answer. Such functions which don't return anything are called void functions.
This is the general form of a function:
function functionName() { statement; statement; etc. }
This is an example of a void function:
function greet() { console.log("Hello, World"); }
To execute the function (also known as calling the function, or invoking the function), you write a statement that calls it.
greet();
I would like to point out that void functions actually do return undefined
because returning something indicates that the function has completed its execution.
The ()
is where we pass the input to the function. When we are defining the function, the input is called a parameter. When we call the function, the input will be the actual value and is called the argument. Here's an example:
function greet(name) { console.log(`Hello, ${name}`); } // Outputs: Hello, Alberta greet("Alberta");
With JavaScript ES6, you can define functions using arrow syntax. Here is our greet()
function defined using arrow syntax:
let greet = () => console.log("Hello, World");
A function with one parameter:
let greet = name => console.log(`Hello, ${name}`); // Outputs: Hello, Monty greet("Monty");
A function with more than one parameter:
let greet = (fname, lname) => console.log(`Hello, ${fname} ${lname}. How are you?`); // Outputs: Hello, Monty Shokeen. How are you? greet("Monty", "Shokeen");
A function with multiple statements:
let greet = (fname, lname) => { let name = `${fname} ${lname}`; console.log(`Hello, ${name}`); } // Outputs: Hello, Monty Shokeen greet("Monty", "Shokeen");
Because an arrow function is an anonymous function, we give our function a name by assigning it to a variable. One of the advantages of arrow functions is that they can make the code more compact.
If we were to write our factorial function as a void function, it could look something like this:
function factorial(x) { let result = 1; while(x > 1) { result *= x; x -= 1; } console.log(result); } // Outputs: 3628800 factorial(10); // Outputs: 479001600 factorial(12); // Outputs: 6402373705728000 factorial(18);
Value-Returning Function
This kind of function returns a value. The function must end with a return statement. This example returns the sum of two numbers.
function add(x, y) { return x + y; }
This is the general form defining a value-returning function:
function functionName() { statement; statement; //... return expression; }
The value of the expression is what gets output by the function. This kind of function is useful when its return value is stored in a variable, etc. Basically, you should explicitly return values from a function if you plan to use that value somewhere else in your code.
Here is our factorial function written as a value-returning function.
function factorial(x) { let result = 1; while(x > 1) { result *= x; x -= 1; } return result; } // Outputs: 3628800 console.log(factorial(10)); // outputs: 479001600 console.log(factorial(12)); // Outputs: 6402373705728000 console.log(factorial(18));
As you can see, we get the same output. The only thing that changes is that we use a return
statement to get our calculated value from the function.
Scope
A variable’s scope is the part of the program where the variable can be accessed. A variable can be local or global. A local variable’s scope is inside the function it was created in. No code outside of the function can access its local variables.
Also, when you use let
or const
to declare a variable, they have block scope. A block is a set of statements that belong together as a group. A block could be as simple as wrapping our code in curly braces:
{ let a = 2; }
The variable a
is local to the block it is in. A block can also be a loop or an if statement. For example:
let a = 1; if (true) { let a = 2; } console.log(a); //1
Because our console statement is in the same scope as our first variable a
, it displays that value, which is 1. It does not have access to the variables inside the if block. Now, consider this example:
let a = 1; if (true) { let a = 2; console.log(a); //2 }
Now 2 will be displayed because the scope of variables that our console statement has access to is within the if block. A function’s parameters are also local variables and can only be accessed by code inside the function. Global variables, on the other hand, can be accessed by all the statements in a program’s file. Here's an example:
let a = 1; function foo () { a = 2; } console.log(a); //1 foo(); console.log(a); //2
In this example, a
is a global variable, and we have access to it inside the foo function. The first console statement will display 1. After calling foo
, the value of a
is set to 2, making the second console statement display 2.
Global variables should be used very little, and ideally not at all. Because global variables can be accessed by any part of a program, they run the risk of being changed in unpredictable ways. In a large program with thousands of lines of code, it makes the program harder to understand because you can’t easily see how the variable is being used. It's better to create and use local variables.
However, if you need to use a variable in multiple places in your program, it is OK to use a global constant. Declaring a variable with the const
keyword prevents it from being changed, making it safer to use. You only need to worry about updating the value of the constant in the place it was declared.
Parameters
Recall that a parameter is a variable that a function uses to accept data. The parameter is assigned the value of a function’s arguments when the function is called. As of ES6, parameters may also be given default values with the format parameterName=value
. In this case, you can call a function without arguments, and it will use default values. For example:
function greet (name="World") { console.log(`Hello, ${name}`); } // Outputs: Hello, World greet();
The spread/rest operator is new to ES6 and can be used to either expand an array or object into individual values or gather the parameters of a function into an array. This is an example of using a rest parameter:
function foo(...args) { console.log(args); } foo( 1, 2, 3, 4, 5); //[1, 2, 3, 4, 5]
Modules
Suppose now you have a file that has over 1,000 lines. The file is organized into functions, but it is difficult to see how they relate to each other.
To group together related behavior, we should put our code in modules. A module in ES6 is a file that contains related functions and variables. Modules let us hide private properties and expose public properties that we want to use in other files. The filename would be the name of the module. Modules also have their own scope. To use variables outside of the module’s scope, they have to be exported. Variables that aren’t exported will be private and can only be accessed within the module.
Individual functions and variables can be exported like this:
export function foo() { console.log(“Hello World”); } export let bar = 82; export let baz = [1,2,3];
Alternatively, multiple functions and variables can be exported with one export statement:
function foo() { console.log("Hello World"); } let bar = 82; let baz = [1,2,3]; export { foo, bar, baz };
To use a module’s variables, you import it into the file. You can specify what you want to import from the module like this:
import { foo, bar, baz } from "foo";
You can also rename your import:
import { foo as Foo } from "foo"; Foo();
Or you can import all of the properties of the module:
import * as myModule from "foo"; myModule.foo();
Review
Functions allow us to divide our programs into smaller programs that we can easily manage. There are two kinds of functions based on their return types: void functions and value-returning functions. A void function returns undefined
. A value-returning function gives us back a value.
Scope is the part of the program where a variable can be accessed. Variables declared inside a function, including the function’s parameters, are local. Blocks also have scope, and local variables can be created inside them.
Variables not enclosed in a block or module will be global. If you need a global variable, it is acceptable to have a global constant. Otherwise, try to contain your code to modules because modules have their own scope. But even better, modules give your code structure and organization.
This post has been updated with contributions from Monty Shokeen. Monty is a full-stack developer who also loves to write tutorials and to learn about new JavaScript libraries.
This content originally appeared on Envato Tuts+ Tutorials and was authored by Alberta Williams
Alberta Williams | Sciencx (2017-08-03T10:15:12+00:00) Learn to Code With JavaScript: Part 4, Functions. Retrieved from https://www.scien.cx/2017/08/03/learn-to-code-with-javascript-part-4-functions/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.