JavaScript: Functions

Functions: Reusable Blocks of Code

Odin status: in the page JS Foundations fundamental part 3. Current reading: 6. Call Stack.

Function
A piece of code that does a single task inside a define block.
Parentheses ()
Functions using parentheses () to encapsulate their block code.
Some common built-in language structure are using () as well. These are not functions. For examples:
  • for loop
  • while or do...while loop
  • if...else statement
Built-in browser functions
Examples
  • myText.replace("dog", "cat")
  • myArray.join(' ')
  • Math.random()
  • alert(message)
  • prompt(message, default)
  • confirm(question)
Methods vs functions
Methods are functions that are part of objects
Custom functions
Functions we defined ourselves in our code. Not inside the browser.
Function declaration
function myFunction() {...code...};
Invoking functions
Invoke = run, activate
myFunction();
Function parameters
Function parameters: variable values needed to be passed into the function block.
Written within the parentheses () and comma separated
Example of function that doesn't require parameter: Math.random()
Example of function that needs parameter: replace("original", "replacement")
Parameters vs arguments
  • Function declaration: Parameters are the variables listed.
  • Calling a function: Arguments are the values passed.
function func (param1, param2) {
    codeblock;
}

func (arg1, arg2); 
Optional parameters
Sometimes parameters are optional. When it is not specified, it wil typically adopt some kind of default behaviour.
For example, function join(). Without defined parameters comma separator is used.
Default parameters
  • Optional parameters in a custom function can be made by defining default parameter using an equal mark = when defining the function.
  • Function declaration:
    function myFunction(name="Kitten") {console.log(`Hello, ${name}!`)};
  • Function invoke:
    myFunction(); // "Hello, Kitten!"
    myFunction("Ruby"); // "Hello, Ruby!"
  • Alternatively, default can be generated inside the code block.
    function myFunction(name) {
        if (name === undefined) {name = "Kitten";}
        console.log(`Hello, ${name}!`);
    }
    myFunction(); // "Hello, Kitten!"
    
  • Using or operator ||
    function myFunction(name) {
        name = name || "Kitten";
        console.log(`Hello, ${name}!`);
    }
    myFunction(); // "Hello, Kitten!"
    
Anonymous functions
Functions without function name
function () {alert("Hello!");}
Often used in the case where a function receives another function as a parameter.
Example: addEventListener() function
Anonymous function example: addEventListener()
This function is used with 2 parameters:
  • First parameter: event name. For example: "keydown"
  • Second parameter: function triggered upon event happens. For example: myFunction
Without anonymous function:
  • function myFunction (event) {output.textContent = `You pressed "${event.key}".`);}
  • textBox.addEventListener("keydown", myFunction);
With anonymous function:
  • textBox.addEventListener("keydown", function(event) {output.textContent = `You pressed "${event.key}".`);});
Arrow function
  • Instead of: function(event) {...codeblock...}
  • You can write: (event) => {...codeblock...}
  • If there's only 1 parameter, you can omit parameter's bracket: event => {...codeblock...}
  • If there's only 1 line of codeblock, you can omit the curly brackets: event => ...codeblock...
  • If the function needs to return a value and only contains 1 line, you can omit the return statement.
    • function doubleItem(item) {return item * 2;}
    • item => item * 2
    • const original = [1, 2, 3];
    • const doubled = original.map(item => item * 2);
    • console.log(doubled); // [2, 4, 6]
Keydown example above can be written as:
  • textBox.addEventListener("keydown", (event) => {output.textContent = `You pressed "${event.key}".`);});
  • textBox.addEventListener("keydown", event => {output.textContent = `You pressed "${event.key}".`);});
  • textBox.addEventListener("keydown", event => output.textContent = `You pressed "${event.key}".`);
Variable scopes
Where a variable can be seen from.
Global scope
Top level outside all functions.
Variables are accessible from everywhere in the code.
Function scope
Variables can only be seen inside function where it is declared.
Loop and conditional scope
They are not really functions even though sharing similar bracketing. The same scoping rules doesn't apply.
Naming a function
  • Function is an action. So the names are usually verb. Keep it brief and accurate. Decribe what the function does.
  • 2 words name in camelCase is common. First word is a verb, second is a noun.
  • Some common first words and their common uses:
    • get – return a value
    • calc – calculate something
    • create – create something
    • check – check something and return a boolean
    • is – is it true or false
  • Examples:
    • showMessage – shows a message
    • getAge – returns the age (gets it somehow)
    • calcSum – calculates a sum and returns the result
    • createForm – creates a form (and usually returns it)
    • checkPermission – checks a permission, returns true/false
    • isPrime – checking a value is a prime or not. Return boolean.
One function one action
  • Limit 1 action per function. When there are 2 actions, better separate them in 2 functions. A third function can be created to combine them.
  • For example:
    • getAge – Let the function only get the age. Don't have it shows an alert of the age.
    • checkPermission – Should only check the permission and return the result. Don't mix it with displaying message Access granted/denied

Function Declaration

function functionName() {code block}
functionName = function() {code block}

Function: A piece of code that does a single task inside a define block.

A function can be assigned like above. () is where arguments are listed. It can be empty if there's no arguments.

functionName
newVar = functionName

To see the value (description/formulation) of a function, we are using functionName without the brackets (). Imagine this is how we do to check primitive variables value too. If we assigning it to a new variable newVar, newVar will now contain the same function as functionName. So without bracket, the function will be assigned/declared. Not run. This is what we are using when we assigning a function to an event handler. We just want to assign the function to the handler. Not to run the function and assign its return value to the handler (which will be undefined if the function doesn't have a return value.)

functionName()
newVar = functionName()

To run the function, use the brackets: functionName(). It will return a return value or undefined if there's no return value. If we are assigning it to a new variable newVar, then newVar value will be that return value (or undefined) instead of assigning the function formulation. The function will be run when loading the page in order to give newVar the return value needed.


Return

Keyword: return
Return value
A value returned by a function upon completing the execusion.
  • A function can have a return value or not. When it does have, there can only be 1 return value.
  • (I guess I can see it like an equation mark. Return value is what's in the right side of equation.)
  • A return value is needed when the purpose of the function is to generate a value that will be proccessed further. This value needs to be available globally to be avaiable for other function to process. (Think of global variable, but not declared, and generated dynamically).
  • Don't add newline between return and the value. A semicolon ; will automatically be added. Making the return an empty one and immediately exit the function without ever reached the value line.
Return without value
Return without value is possible. It exit the function immediately.

Function Expression

Function declaration
function sayHi() {alert("Hello");}
The function is declared as a separate statement in the main code flow.
  • When Javascript run the script, it will first look for global function declaration and creates it. Think of "initialization stage". After all function declarations are processed, the code is executed.
  • The consequence is, function declaration can be called earlier than it is defined
Function expression
let sayHi = function() {alert("Hello");};
The function is created inside an expression or inside another syntax construct.
  • Function expression is created when code execution reaches it and it is only useable from that moment.
For examples:
  • As a variable value (the right side of assignment expression =)
    let sum = function(a, b) {
        return a + b;
    }
  • As an argument (check out following function callback subchapter)
A function is a value
Meaning we can work it out just like a value.
Example with function declaration
function sayHi() {alert("Hello");}
let func = sayHi;

func(); // Hello
sayHi(); // Hello
Example with function expression
let sayHi = function() {alert("Hello");};
let func = sayHi;

func(); // Hello
sayHi(); // Hello
Which one to use? Function declaration or expression?
  • In general, consider function declaration first. Because it can be called from everywhere, also have a better readability.
  • Use function expression only when function declaration doesn't fit the task, like in the examples below.

Function Expression: Inside Code Block

Function declaration
In strict mode, when a function declaration is within a code block, it's visible everywhere inside that block, but nout outside of it.
"use strict"
let age = prompt ("Age:", 18);

if (age < 18) {
    function message() {
        alert("Access denied.");
    }
} else {
    function message() {
        alert("Welcome!");
    }
}

message(); // Error: message is not defined
Function expression
To make the function accessible from outside, we can use function expression instead, and declaring it globally.
"use strict"
let age = prompt ("Age:", 18);
let message;
if (age < 18) {
    message = function() {
        alert("Access denied.");
    }
} else {
    message = function() {
        alert("Welcome!");
    }
}

message(); // Now it works
Ternary with function expression
"use strict"
let age = prompt ("Age:", 18);

let message = (age < 18) ?
    function() {alert("Access denied.");} : 
    function() {alert("Welcome!");};

message(); // It works

Function Expression: Callback Functions

Action based on true / false input
confirm: true / false
  • If true: run function A
  • if false: run function B
Callback functions / callbacks
We can pass a function and expect it to be "called back" later if necessary. Like function A to be called in the case "OK" is pressed, and function B for "Cancel".
Function scheme
function choice(question, yes, no) {
    if (confirm(question)) yes()
    else no();
}
With the callback functions
Arguments functionA and functionB are called the callback functions, or in short, callbacks.
function choice(question, yes, no) {
    if (confirm(question)) yes()
    else no();
}

function functionA() {alert("You pressed 'OK'");}
function functionB() {alert("You pressed 'Cancel'");}

choice("Which one will you press?", functionA, functionB);
Using function expressions
We can use function expressions to express those callbacks directly as the arguments.
function choice(question, yes, no) {
    if (confirm(question)) yes()
    else no();
}

choice(
    "Which one will you press?", 
    function() {alert("You pressed 'OK'");}, 
    function() {alert("You pressed 'Cancel'");}
);
The functions are anonymous and can't be called with other ways. But sometimes this is just what we need and it provides a clear, short, to the point codes.

Arrow Function

Function declaration
function sayHi() {alert("Hello");}
Function expression
let sayHi = function() {alert("Hello");};
Arrow function
let sayHi = () => {alert("Hello")};
Codeblock only 1 line: curly brackets not necessary
let sayHi = () => alert("Hello");
Codeblock with return
  • Function expression
    func = function () {
    codeblock;
    return value;
    }
  • Arrow function
    func = () => {
    codeblock;
    return value;
    }
  • In multiline codeblock with return, the word "return" is necessary.
Codeblock with only return: curly brackets and "return" not necessary
func = () => value;
Function with parameters
func = (param1, param2) => value;
    multiply = function (a, b) {
        return a*b;
    }                           // same code
    
    multiply = (a, b) => {
        return a*b;
    }                           // same code
    
    multiply = (a, b) => a*b;   // same code
    
Function with only 1 parameter: parentheses not necessary
func = param1 => value;
greetings = function (userName) {
    return "Hello, " + userName + "!";
}

greetings = userName => "Hello, " + userName + "!";
Remember: For function with no parameters, parentheses are necessary.
Task on Javascript.info
Replace function expression below with arrow function
function ask(question, yes, no) {
    if (confirm(question)) yes();
    else no();
}
    
ask(
    "Do you agree?",
    function() { alert("You agreed."); },
    function() { alert("You canceled the execution."); }
);
Arrow function:
let ask = (question, yes, no) => confirm(question)? yes() : no();

Call Stack

JavaScript Call Stack
  • Javascript's mechanism to keep track of the function calls.
  • JS engine uses a call stack to manage "execution context"
Execution context
  • Global execution context
  • Function execution context
LIFO: Last In First Out
  • Script executed -> JS engine creates a global execution context and pushes it on the top of call stack.
  • When a function is called -> JS engine creates a function execution context for that function and pushes it on top of the call stack, and starts executing the function.
  • If that function calls another function, JS engine will creates a new function execution content for the new function and pushes it on the top of the call stack, and starts executing that new function.
  • And this go as deep as needed.
  • When the function execution is completed, JS engine pops it off the call stack.
  • It resumes the execution in the parent function where it left off, end when it's done, the engine pops it off the call stack.
  • At the end, script is finished, the global execution context is popped off too, call stack is empty, script stops executing.
function add(a, b) {
    return a + b;
}

function average(a, b) {
    return add(a, b) / 2;
}

let x = average(10,20);
JavaScript Call Stack by JavaScript Tutorial
Stack Overflow
  • Call stack has a fixed size. It depends on the implementation by the host environment. Either web browser or Node.js.
  • If number of the execution contexts exceeds the size of the stack, a stack overflow error will occur.
  • An example is a recursive function that has no exit condition is executed. It keeps opening a new functino execution context without closing Any.
    function fn() {
        fn();
    }
    
    fn();
    
Asynchronous JavaScript
  • JS is a "single threaded" programming language. Meaning JS engine has only 1 call stack. Therefore it can only do 1 thing at a time.
  • When executing script, JS executes code from top to bottom, line by line. This is "synchronous".
  • Asynchronous means, Javascript engine can execute other task while waiting for another task to complete, using "event loop". For example:
    • Request a data from a remote server
    • Display a spinner
    • When data is available, display it on the webpage.

References