2. Functions
Every function in JavaScript is a Function object. The main point to take away here is that functions in JavaScript are values themselves and can be manipulated just like values. This makes JavaScript an incredibly expressive language; here's where the real power is.
2.1 Defining and Calling Functions
We can define a function using a function declaration. The following function declaration defines a function called makeSomeNoise that takes in a single parameter called yourName.
function makeSomeNoise(yourName) {
return "Make some noise for " + yourName + "!!";
}
// let's call it now
makeSomeNoise("Sinho Chewi"); // --> "Make some noise for Sinho Chewi!!"
We can also use a function expression, which is just like a normal expression but returns a function value, which can be assigned to a variable or further manipulated:
var makeSomeNoise = function(yourName) {
return "Make some noise for " + yourName + "!!";
}
makeSomeNoise("Anant Sahai"); // --> "Make some noise for Anant Sahai!!"
2.1.1 Anatomy of a Function Call
Going back to the philosophy of avoiding crashing at all costs, we observe that in JavaScript, functions can be called with less or more arguments than they ask for. Consider the following code:
function iWantTwoArguments(a, b) {
console.log(a, b);
}
// both of the below would throw exceptions in Python!
// but they execute without complaining.
iWantTwoArguments();
iWantTwoArguments(1, 2, 3, 4, 5);
There are no errors! But then how do we know if a function was called as intended or with extra/less arguments? We can check if specific parameters were omitted by seeing if they evaluate to undefined:
function iWantTwoArguments(a, b) {
if (typeof a === "undefined" || typeof b === "undefined") {
return console.log("Missing an argument!");
}
console.log(a, b);
}
We can also check the arguments object, which is an array-like object (more on arrays in the next section):
function iWantTwoArguments(a, b) {
if (arguments.length !== 2) {
return console.log("Did not receive exactly 2 arguments");
}
console.log(a, b);
}
Finally, we can combine the arguments object with rest parameters to let functions accept an indefinite number of arguments.
function printMyArguments(...args) {
console.log(args); // prints my arguments in the form of an array.
}
2.2 Manipulating Functions
2.2.1 Functions as Values
Just like in Python, functions can be passed around as arguments, returned from other functions, or be assigned to variables.
function makeAdder(increment) {
return function(inputNumber) {
return inputNumber + increment;
}
}
var incrementByOne = makeAdder(1);
var incrementByTwo = makeAdder(2);
incrementByOne(50); // --> 51
incrementByTwo(50); // --> 52
2.2.2 Functional Operations
Since functions are values, we can apply some special operations to them to create new, more complex functions. Here are some such operations:
- Function binding - Create a new function that is bound to a particular scope or is already applied to particular arguments.
- Function prototype calling - Call a function within the context of a particular scope with particular arguments.
2.3 Control
2.3.1 Conditional Statements
JavaScript's syntax for if-else statements take the following form:
if (CONDITION) {
// STATEMENTS
} else if {
// ...
} else {
// ...
}
Conditional expressions are surrounded by parentheses and the statements to be executed if the condition is true should be surrounded by curly braces.
if (currentClass === "61A") {
console.log("ez pz lemon sqz");
} else if (currentClass === "61B") {
console.log("okey dokey lowkey nopey");
} else if (currentClass === "70") {
console.log("difficult difficult lemon difficult");
} else {
console.log("???!!???!!???");
}
Observe that the above code only really cares about the value of a single expression - the value of the variable currentClass. We can make decisions based on different cases for a single expression using the switch statement as well, which is essentially syntactic sugar for this special if-else situation. The expression inside switch (EXPR) gets evaluated and the result is matched sequentially against each case VALUE:. If EXPR == VALUE then the code inside that case block is executed. If the default: block is reached, then that code will be executed regardless of the expression's value.
switch (currentClass) {
case "61A": {
console.log("ez pz lemon sqz");
break;
}
case "61B": {
console.log("okey dokey lowkey nopey");
break;
}
case "70": {
console.log("difficult difficult lemon difficult");
break;
}
default: {
console.log("???!!???!!???");
break;
}
}
Notice the break statements at the end of each case block. If break is omitted then the program continues matching the expression with cases even after a case block has been executed. Sometimes this is useful but often this will result in the default block always being executed. Read the documentation on switch for more.
So far our conditional controls have taken the form of statements that are executed rather than evaluated. But we can also express conditions in the form of expressions that are evaluated to a value using the conditional (ternary) operator:
var difficulty = (currentClass === "61A") ? "ez pz lemon sqz" : "super difficult";
// the above is equivalent to the following if-else statements::
if (currentClass === "61A") {
difficulty = "ez pz lemon sqz";
} else {
difficulty = "super difficult";
}
2.3.2 Loops
While loops execute the body of the loop as long as a given condition is true:
var i = 0;
while (i < 10) {
console.log("Currently at the " + i + "th iteration of the loop");
i++;
}
Notice in the above code that our loop executes 10 times, and to do this, we needed to do the following:
- Declare and initialize a "counter variable" before our loop begins.
- Check a condition at the start of each iteration of the loop.
- Increment our counter variable at the end of each iteration.
We can put all of this code into its own block because all we really care about is the content of the loop. Let's do this using a for loop:
for (var i = 0; i < 10; i++) {
console.log("Currently at the " + i + "th iteration of the loop");
}
Sometimes when we're in the middle of an iteration of a loop, something happens that makes us want to break out of the loop. We can do this using a break statement:
for (var i = 0; i < 10; i++) {
console.log("Currently at the " + i + "th iteration of the loop");
if (i === 7) {
break; // this stops the loop at the end of the 7th iteration instead of the 10th
}
}