What is a function

A function is a self-contained collection of statements that run as a single unit. A function is created with an expression that starts with the keyword function. Functions have a set of parameters and a body, which contains the statements that are to be executed when the function is called.

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects, and as such, can be passed around and assigned just like any other objects.

Lets create a function with a single parameter x and assign it to a constant called square.

const square = function(x) {

//function body
return x * x;

//the return statement stops the execution of the function and produces an output
};


The function created above takes in one argument x and returns x*x

Calling vs referencing a function

Calling a function is simply a matter of writing the function name along with the coresponding arguments in place of the parameters i.e square(3).
Now lets create a function, call the function and print the output to console.

const square = function(x) {
return x * x;
};
//calling the function and logging the result to console
console.log(square(3)); //prints 9


In the above function call, 3 is the argument that is being represented by the parameter x in the function definition. When you follow a function identifier with parentheses, JavaScript knows that you’re calling it: it executes the body of the function.

Arguments are passed to functions by value. Which means if the function changes the value of an argument, this change is not reflected globally or in the calling function.

const square = function(x) {
return x * x;
};

let y = [3, 4, 5];
//call the function on the second value of array y
console.log(square(y[1])); //prints 16

//after the call, the array remains the same
console.log(y); //prints [3, 4, 5 ]


When you don’t provide the parentheses (), you’re simply referring to the function just like any other value, and it’s not invoked. Lets print a reference of the function square.

const square = function(x) {
return x * x;
};
console.log(square); //prints [Function: square]


The importance of referencing a function is that it allows you:

1. To assign a function to a variable, which allows you to call the function by another name:
const square = function(x) {
return x * x;
};

let sqr = square; //assign function square to variable sqr

//then call sqr()
console.log(sqr(9)); //prints 81

1. To assign a function to an object property:
const square = function(x) {
return x * x;
};

const ob = {}; //empty object
ob.s = square; //assign function square to object property s
console.log(ob.s(8)); //prints 64

1. To add a function to an array:
const square = function(x) {
return x * x;
};

const arr = [4, 2, 8];
arr[1] = square; // arr is now [4, function square, 8]
console.log(arr[1](7)); //prints 49


Anonymous functions

Functions can either be named or anonymous. When a function is defined without a name, it’s known as an anonymous function. The function is stored in memory, but the runtime doesn’t automatically create a reference to it for you.

//anonymous function
function(x) {
return x * x
}


Assigning an Anonymous Function to a Variable

A very common use of anonymous functions is to assign them to variables:

//Assigning an anonymous function to a variable square
let square = function(x) {
return x * x;
};


Anonymous Function as a Parameter to Another Function

Some functions may accept a reference to a function as a parameter. These are sometimes referred to as
"dependency injections" or "callbacks", because it allows the function your calling to "call back" to your code, giving
you an opportunity to change the way the called function behaves.

var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } );
console.log(doubledNums); //prints [ 0, 2, 4 ]


Lets go through the code above step by step.

1. nums is an array of numbers.
2. the Array object’s map function
allows you to iterate over each element of an array, then build a new array by applying a transform function to each
element.
3. In this case, the map function is taking in an anonymous function
function(element){ return element * 2; } as a parameter.

Function declaration

Another way of creating a function is by using function declaration which allows us to created named functions. Instead of

const user1 = function(name){
return name+"@sytech.co.zw";
};


we can

function user2(name){
return name+"@innotech.co.zw";
}  //no semicolon is required


lets call both functions and see;

console.log(user1("sydney")); //prints sydney@sytech.co.zw
console.log(user2("sydney")); //prints sydney@innotech.co.zw


This type of function declaration works even though the function is defined below the code that uses it. This is called hoisting.

console.log(fact()); //prints you can be on top for once

function fact(){
return "you can be on top for once";
}


This is sometimes useful because it offers the freedom to order code in a way that seems meaningful to you without having to worry about having to define all functions before they are used.

Both named and anonymous functions can be assigned to variables:

//named function
var namedFunc = function product (a, b) {
return a * b;
}

//anonymous function
var anonFunc = function (a, b) {
return a * b;
}

console.log(namedFunc(2, 3));
//prints 6

console.log(anonFunc(2, 3)); //prints 6


Arrow functions

Instead of the function keyword, we can use an arrow (=>) made up of an equal sign and a greater-than character. Arrow functions are always anonimous.

Arrow functions are shorter

var fact = () => "Arrow functions are shorter";


as compared to

var fact = function () {
return "Arrow functions are shorter";
};


const crt = function (a,b){
return a + b;
};


we can

const arw = (a, b) =>a + b ;

console.log(crt(2,4)); //prints 6
console.log(arw(2,4)); //prints 6


without parameters

const wpr = () =>{
console.log("hey");
};

wpr(); //prints hey


Function constructor

Functions can also be created using the new keyword.

const y = new Function("x", "z", "return x+z");
console.log(y(2,4)); //prints 6


Function parameters go first, and the body is last. All arguments are strings and we put them in quotes. All other previous forms of function creation requires the programmer to write the function code in the script. But Function constructor allows the programmer to turn any string into a function and execute it.

let str = "return(2+3)";

let conFunc = new Function(str);

console.log(conFunc()); //prints 5


Function scope

When you define a function, it creates a scope. Everything defined within the function is not accessible by code outside the function. Only code within this scope
can see the entities defined inside the scope.
This means that parameters exist only in the function, even if they have the same name as variables outside of the function.
Consider the following code:

let x = 10; //variable x with a value of 10

function solve(x){
console.log(x + 4); // now this x takes the value of the argument and is different to the x outside the function
};

solve(); //prints NaN


What if we do an assignment of x inside the function.

let x = 10; //variable x with a value of 10

function solve(x){
x = 5; //lets assign 5 to x inside the function
console.log(x);
};

solve(); //prints NaN
console.log(x); //prints 10


The x outside the function is not affected by the assignment of the x inside the function.

Another example

function greet() {
var msg = "hello";
console.log(msg); //prints hello
}
console.log(msg); // ReferenceError: msg is not defined


When JavaScript tries to resolve a reference or variable, it starts by looking for it in the current scope. If it cannot find
that declaration in the current scope, it keeps climbing up one scope after the other until it finds it. If the JavaScript reaches the global scope and still cannot find the reference, a reference
error will be thrown.

More functions

Lets create a function that calculates the cube of a number

const cube = function(x){
return x * x * x;
};
console.log(cube(4)); //prints 64


Anything within a function body but after the return statement is unreachable

const mixed = function(x){
return x + x; //execution stops here
return x + 10; //unreachable statement
};

console.log(mixed(5)); //prints 10


Execution breaks out of the function at the first return statement (return x + x), making the second return statement (return x + 10) unreachable.

A function can have no parameters at all. Lets create a function that barks without an argument provided.

const bark = function(){
return "woof, woof, woof";
};
console.log(bark()); //prints woof, woof, woof


A function can have multiple parameters. For example lets create a function that calculates the determinant of a 2 x 2 matrix

const determinant = function(a, b, c, d){
return a*d - b*c;
};
console.log(determinant(1,2,3,4)); //prints -2


Now lets create a function that determines whether a matrix is singular or not.

const isSingular = function(a, b, c, d){
return a*d - b*c == 0;
};


One advantage of a function is that you can call it as many times as you want, thereby reducing code size as you wont be repeating the logic. Another advantage is that when you want to change something in the logic, you change in one place only ( in the function definition).

console.log(isSingular(1,2,3,4)); //prints false
console.log(isSingular(2,1,4,2)); //prints true


Some functions have no return statement. For example, the following print function does not return anything but logs directly to console.

const print = function(a){
console.log(a);
};

print("Hi Javascript"); //prints Hi Javascript


Functions that don’t have a return statement at all, return undefined. That is why

console.log(print("Hi")); //prints Hi  undefined


A return keyword without an expression after it will cause the function to return undefined.

const undef = function(){
return;
};
console.log(undef()); //prints undefined


Optional and default arguments

If you provide more arguments than needed by a function, Javascript ignores the extra arguments. Lets create a function which takes 1 argument

function printSqrt(num) {
console.log(Math.sqrt(num));
}

printSqrt(5); //prints 2.23606797749979


Now lets call the function with 3 arguments instead of 1

printSqrt(3, "number", "third"); //prints 1.7320508075688772


Javascript computed the square root of the first argument and ignored the rest.

If you pass too few, the missing parameters get assigned the value undefined.

Lets call the function again with 0 arguments instead of 1

printSqrt(); //prints NaN
//the square root of undefined is NaN


However you can provide default values for optional arguments.
For example if it is given that the velocity of an object after t seconds is given by v=2t+3, lets create a function that prints the velocity of the object after a given time t.

function getVelocity( t = 0){
console.log(2*t + 3);
}

//velocity after 5 seconds
getVelocity(5); //prints 13

//now of we call it with no argument, t defaults to 0
getVelocity(); //prints 3

function greet(msg='Mamukasei') {
console.log(msg);
}

greet(); //prints Mamukasei
greet(undefined); //prints Mamukasei
greet('Good morning'); //prints Good morning