JavaScript Functions: The Basics
Differences between C++ and JavaScript functions:
- No type needs to be defined in JavaScript functions - neither in the signature, nor among the arguments!
- The return keyword is used! Most commonly, we define values/variables to achieve what we want to yield from the function, and then return them.
- While not a difference, it is very common to pass a function as an argument in JavaScript
Quick Quiz: Scope in JavaScript
The code for the Show Answer below is from one of the answers posted here. The code used in the JavaScript file is currently (slightly) beyond my scope!
- What is printed to the console when this code runs?
let animal = "Giant Pacific Octopus"; function observe(){ let animal = "Pajama Squid"; console.log(animal); } observe();
- What is the result of running the following code?
const creature = "Common Sea Dragon"; function scubaDive(){ const creature = "Spanish Dancer"; //A type of sea slug console.log(creature); } scubaDive();
- What two values are printed to the console?
let deadlyAnimal = "Blue-Ringed Octopus"; function handleAnimal() { let deadlyAnimal = "Scorpionfish"; console.log(deadlyAnimal); } handleAnimal(); console.log(deadlyAnimal)
- What JavaScript was used for the answer button? (BONUS!)
Regarding Scope and const/let/var
There's an interesting difference between the use of var and let/const in JavaScript. If we use let/const, our variables generally stay within their scopes. For example, in a for-loop for(let i = 0; i < 4; i++), the i variable wouldn't be accessible outside of the block over which it iterates. However, if we use for(var i = 0; i < 4; i++), we would be able to output i later (it, presumably, would be 4).
- 'var' is function-scoped, meaning that a variable declared with 'var' within a function is only accessible within that function. Variables declared with 'var' are also hoisted, meaning that they are moved to the top of their scope, and can be accessed before they are declared in the code.
- 'const' is used to declare a variable that cannot be reassigned, while 'let' is used to declare a variable that can be reassigned. Both 'const' and 'let' are block scoped, meaning that a variable declared with 'const' or 'let' within a block is only accessible within that block.
- In modern JavaScript, it is generally recommended to use 'const' by default, and only use 'let' when you know a variable needs to be reassigned. 'var' is not considered best practice in modern JavaScript, and it is recommended to avoid using it.
Function Expressions
In JavaScript, functions are considered as values! In this language, we can return functions as values, just as we return numbers!
- Definition: a function expression is a way to define a function and assign it to a variable.
- The most basic example is shown in the code below. Notice how a function expression can be
anonymous, or it can have a named identifier. An anonymous function expression is a function
without
a name, and it is usually assigned to a variable like below. So, we created a function
expression and assigned it to the variable
add. In this example, the function function(a, b) { return a + b;
} is an anonymous
function expression, and it is assigned to the variable add. This function can be invoked by
calling
add(1, 2), which would return 3.
const add = function(a, b) { return a + b; }; console.log(add(1, 2));
-
A named function expression is a function that has a name, and it is also assigned to a
variable.
The name of the function is only accessible within the function's scope. In this example, the
function function multiply(a, b) { return a * b; } is a
named function
expression, and it is assigned to the variable multiply. This function can be
invoked
by calling
multiply(2, 3), which would return 6. It is important to note that a named function
expression
cannot be invoked before it is defined,
unlike function declaration.
let multiply = function multiply(a, b) { return a * b; }
- Function Expressions are commonly used in JavaScript when a function is defined inside another function, or if the function is used only in a specific scope. It is also useful when you want want to assign a function to a variable and pass it as an argument to another function or return it from a function.
Function Expressions: Advanced Topics
- Advanced Topic 1: Function expressions could also be used with IIFE(Immediately-Invoked Function Expressions) which allows us to execute a function immediately after it is defined.
- Advanced Topic 2a: Another way of writing function expressions is by using the arrow
function
notation, which is more concise and also introduced in ECMAScript 6
(ES6). Here is an example of the
same function expression written with arrow function notation:
const sum = (a, b) => a + b;
- Advanced Topic 2b: Function expressions are used frequently in JavaScript, and one of the most
common use cases is to pass a function as an argument to another function, like
setTimeout or
Array.prototype.map. They also can be used for creating
closures
(see next point!), creating
functions on the fly, or
to use it as a return value. In this example, we defined two functions multiply and divide as
function expressions, and then
we
defined another function calculator which takes 3 arguments a, b and operator which is a
function,
and it applies the function to a and b and return the result.
const multiply = (a, b) => a * b; const divide = (a, b) => a / b; const calculator = (a, b, operator) => operator(a, b); console.log(calculator(2,3,multiply)) console.log(calculator(10,5,divide))
- Advanced Topic 3: In JavaScript, a closure is a function that has access to the
variables in
its
parent scope, even after the parent function has returned.
A closure is created when a function is defined inside another function, and
the
inner function has
access to the variables of the outer function. Here is an example:
function outerFunction(x) { let innerVariable = x; return function innerFunction() { console.log(innerVariable); } } const myClosure = outerFunction(10); myClosure(); // logs "10"
- Creating private variables that can only be accessed by privileged functions.
- Creating function factories that return different functions with different behavior.
- Implementing data privacy and encapsulation
- Creating and returning function with an already set context or scope.
Higher Order Functions
A higher order function is a function that takes one or more functions as arguments, and/or returns a function as its result.
In JavaScript, functions are first-class citizens, meaning that they can be treated just like any other data type, such as a number or a string. This means that you can pass functions as arguments to other functions, return functions as the result of other functions, and assign them to variables.
Let's look at a simple example:
function callTwice(func){
func();
func();
}
function rollDie(){
const roll = Math.floor(Math.random() * 6) + 1;
console.log(roll);
}
callTwice(rollDie);
Here, we're passing the rollDie function as an argument. Important: we use rollDieHigher Order Functions: Returning Functions
So, a higher-order function can also return a function!. Here's another example of a simple higher-order function that takes a function and a number as arguments, and returns a new function that multiplies the number by the result of the original function:
function multiplyBy(factor) {
return function(number) {
return number * factor;
};
}
const double = multiplyBy(2);
console.log(double(5)); // logs 10
In this example, multiplyBy is a higher-order function because it takes a function
as
an argument (in
this case, the function is just number) and returns a new function as its result.
We
assigned the
returned function to the variable double and when we call
double(5) it
returns 5*2=10
Higher-order functions are a powerful feature of JavaScript and are used frequently in functional
programming. They allow you to write reusable and composable code that can be easily understood,
tested,
and maintained. Some examples of higher-order functions that you might use in JavaScript include
Array.prototype.map, Array.prototype.filter,
Array.prototype.reduce and setTimeout which take a function
as an argument and returns a new function as a result.
In summary, a higher-order function is a function that either takes one or more functions as
arguments
or returns a function as a result. They allow you to write reusable and composable code and are
widely
used in JavaScript.
In the course, the following example is used:
function makeMysteryFunc(){
const rand = Math.random();
if(rand>0.5){
return function(){
console.log('Congrats! I'm a good function!');
console.log('You win a million dollars!');
}
}else{
return function(){
alert('Uh oh! You have been infected by a virus!');
alert('Stop trying to close this window!')
alert('Stop trying to close this window!')
alert('Stop trying to close this window!')
alert('Stop trying to close this window!')
alert('Stop trying to close this window!')
}
}
}
So, using something like:
let mystery = makeMysteryFunc();
...would allow us to call mystery() itself, and see what we got: the function was
returned by the makeMysteryFunc function!
A better example is illustrated with this function:
function makeBetweenFunct(min,max){
return function(num){
return num>=min && num<=max;
}
}
This function takes in two arguments (min and max), and return a function that can be used to verify
if
a value falls between the specified min and max values.
For example, we could define some specific age ranges (ages correct in 2023*) like so:
function (note how the keyword isn't needed)
function const genAlpha = makeBetweenFunct(0,13);
const genZ = makeBetweenFunct(14,26);
const millenial = makeBetweenFunct(27,42);
const genX = makeBetweenFunct(43,58);
const boomer = makeBetweenFunct(59,77);
const silentGen = makeBetweenFunct(78,94);
const greatestGen = makeBetweenFunct(95,120);
We can call these various functions, and check out what they return!
genZ(25) returns true!
millenial(44) false
genX(69) false
boomer(100) false
silentGen(92) true
greatestGen(37) false
Methods
In JavaScript, a method is a function that is a property of an object. In C++, a member function is found in a class, and is similar! Both define behavior for objects, and they can be called on an instance of the class or object! (But let's focus on the JavaScript!!!)
In JavaScript, you can define a method as a property of an object, like this:
const myObject = {
myMethod: function() {
// method logic here
}
};
ANOTHER EXAMPLE:
const myMath = {
PI:3.14159;
square:function(num){
return num*num;
},
cube:function(num){
return num*num*num; (Or num**3) ** being like ^
}
}
We can call these using myMath.PI (as one example), or myMath.square(5) (giving, hopefully, 25!).
One key thing: objects are everywhere in JavaScript! An array is, by itself, technically an object!
- Define an object called square, which will hold methods that have to do with the geometry of squares. It should contain two methods, area and perimeter. area should accept the length of a side (all sides are the same in a square) and then return the side squared. perimeter should accept the length of a side and return that side multiplied by 4.
The this keyword
this refers to the object that the current function or method is operating on. It is often used to access properties and methods of said current object.
In this example, the 'sayHello' method uses the this keyword to access the name property of the person object, and prints 'Hello, my name is Bobby'
let person = {
name: 'Bobby',
age: 25,
sayHello: function() {
console.log('Hello, my name is '' + this.name);
}
};
person.sayHello(); // Output: 'Hello, my name is Bobby'
Unfortunately, it's not all that simple! this's value changes depending on how the function is called.
The Window Object?
The window object can be thought of as the browser window. It's the blobal object in web browsers, and is automatically created by the browser: and available to all JS code running on the page.
The window object refers to various browser-related functionalities, such as the URL, web page's history, and the ability to create/manipulate browser windows and dialogs.
It also provides access to the document object, which represents the web page's Document Object Model (DOM), and allows you to manipulate the elements of the page.
For example, this code uses window.location to redirect the browser to a new URL:
window.location = "https://www.backToWorkQuick.com";
This one uses the window.alert() method to display an alert dialog with a message:
window.alert("Greetings Friend!");
NOTE: window is only available in the browser environment, and not in other JS environments like node.js
Try/Catch: Error Handling
The try...catch statement is comprised of a try block and either a catch block, a finally block, or both. The code in the try block is executed first, and if it throws an exception, the code in the catch block will be executed. The code in the finally block will always be executed before control flow exits the entire construct.
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// Expected output: ReferenceError: nonExistentFunction is not defined
// (Note: the exact output may be browser-dependent)
}
Another example:
function yell(msg){
try{
console.log(msg.toUpperCase().repeat(3));
}catch(e){
console.log(e);
console.log("Please pass a string next time!");
}
}