Function Principle
We declare functions in JavaScript using keyword: "function". Usually a function has a name but there are cases when function do not have a name.This is called "anonymous" function. After function name we must specify a list of parameters.This list is enclosed in round paranthesis and parameter names are separated by comma.After the parameter list we open the function block using squigly brackets {...}.
Next we define a function and an expression that call the function . A return statement execute first expression before returning the result to the function call. The second expression is used in assignment statement. It is also the function call.On last statement we verify value of x using console message.
/* define a function */
function myFunction(p1, p2) {
return p1 * p2; //multiplication
}
/* call a function */
let x = myFunction(5, 5);
console.log(x); // 25
The JavaScript function can be call using operator: () after function name. Enclosed in these parenthesis you can use literals, variables or expressions, or not. Remember that a JavaScript function can be located in a <script> or in a file. There are 3 basic ways to call a JavaScript function.
A function can have no parameters, one or several parameters. The parameters can can have initial values defined with "=" after parameter name. In next example p2 has default value 10. Parameters with default value are optional. Parameters with no default value are mandatory. In next case, p1 is mandatory
/* parameter p2 is optional */
function myFunction(p1, p2 = 10) {
return p1 * p2;
}
/* test function invocation */
let x = myFunction(5, 5);
let y = myFunction(5);
console.log(x); //expected 25
console.log(y); //expected 50
A function can calculate a value and return value back to the caller. We use "return" keyword. In the previous example we have used an expression to return the result of multiplication between the two arguments. Results can be ignored in JavaScript. That means you can use a function like you normally use a procedure in a procedural language.In this case, maybe the function has side-effects that we want.
JavaScript functions can create multiple results using JSON notation. This is anonymous block enclosed in curly brackets and separated by comma. Actually in this case the result is an anonymous object that contains several values as attributes.We can unpack these values using assignment and destructuring.
Capture results using anonymous object:
// return two results as object
function two(a, b) {
return {a, b};
};
// capture 2 results
let result = two(4,7);
// display attributes
console.log(result.a); // 4
console.log(result.b); // 7
Capture result using destructuring:
function f() {
return [1, 2];
}
let [a, b] = f();
console.log(a); // 1
console.log(b); // 2
Normally a function is using the parameter for input, but sometimes it is useful to use the parameters for output. That means instead of using the return statement to return a result, you assign the result to the parameter. Output parameters can be used to propagate multiple results back to the caller.
//prepare output variable
let output
function get_back(callback) {
//execute callback function
callback({value:"yes"});
}
//call a function with call-back parameter
get_back((result) => {
output = result;
})
//verify output value
console.log(output.value);
Notes: In previous example I have used many things you may not be yet familiar with. The output parameter has name: result and is parameter of an anonymous arrow function. The arrow function is declared with "=>" that looks like an arrow. This function is transmitted to get_back() as callback function having the name: callback for this case,but could have any other name.
JavaScript can be used as a functional programming language. This is very good feature of JavaScript. It may be difficult to understand at the beginning. Pay attention and memorize the fundamental concepts of functional programming, then use the examples to understand more:
Concepts:
Functions that manipulate other functions are called: "high order functions".
In this example we use a higher order function to create a closure. The closure is a function that can create another function. The created function is enclosed in a closure and it has special properties that makes its behavior unique.
// define high order function
function counter() {
var count = 0;
return {
getCount: function getCount() {return count;},
increment: function increment() {count += 1;
};
};
};
// capture two closures
let closure = counter();
// use first closure
closure.increment(); //increment once
closure.increment(); //increment twice
// use second closure
console.log(closure.getCount()); //2
Note: This example demonstrate how to create two functions: increment() and getCount() that are encapsulated into an anonymous object created by a single return statement. Read the concepts below to understand better what is happening here:
A "callback function" is a parameter of a high order function. It is called "call back" since it can be invoked from the higher order function. Callback functions can be anonymous functions or arrow functions that look like an expression. If you do not pay attention to this you may read others people code and do not even realize that a function need a callback parameter.
// higher order function:
function bar(foo, a, b) {
return foo(a,b);
};
// normal function
function sum(x, y) {
return x+y;
}
// use normal function for callback
test = bar(sum, 4, 3)
console.log(test); // 7
// use function expression to create callback
test = bar( function(x,y) {return x+y},2,2)
console.log(test); // 4
// use arrow function to create callback
test = bar( (x,y) => {return x+y},4,4)
console.log(test); // 8
Note: Example above is using new concepts to create callback functions:"expression function" and "arrow function". These two kind of functions can be named or unnamed. In our case the name of the callback function will be "foo" because is the name of the formal parameter of the high order function that is "bar".
An expression function is a function that is created at runtime using an expression. Expression functions can be assigned to variables and executed later. The declaration of expression functions is very unusual. Read the example to understand how "foo" is in fact a function.
// create expression function foo
const foo = function(x,y) {return x + y};
// test expression function
console.log( foo(1,3) ); // 4
console.log( foo(4,4) ); // 8
An arrow function is using symbol "=>" to associate a list of parameters with an expression. In this case the keyword "function" is missing, but the expression is actually assigned to a variable that becomes function. The variable name can be executed later as a function with parameters and it can return a result.
// create arrow functions
const f = (x,y) => { return x + y };
const g = (x) => { return x };
const h = () => { return 1 };
// single parameter do not require ()
const p = x => { return x };
// test arrow functions
console.log( f(4,4) ); // 8
console.log( g(4) ); // 4
console.log( h(4) ); // 1
console.log( p(7) ); // 7
// you can even do this:
test = ((a, b) => {return a + b})(4,2);
console.log(test); // 6
Note: We have used the new keyword: "const" to declare expressions. This will help to avoid overriding by mistake an expression function that was already defined. You can also use "let" to create a handler for the expression functions.A common mistake is to use "var". This enable you to recreate a function in a loop, over and over again. This works, but the performances could be miserable. It is a very bad mistake easy to avoid if you use "const".
Homework:
Try the next example and observe that it does not produce the right result. Then fix the code and run it again.The solution of the problem is explained in the comments. So read the solution and try to understand the code.This example was created to demonstrate how to use output parameters.
I hope you have enjoy learning about JavaScript functions. Now you should know to create and use functions in your scripts.Next we will larn about control flow and structured programming.Take a break and continue later. Thanks for reading!
A generator in JavaScript is a function that can be paused and resumed at will. This is done using the yield keyword. When a generator function is called, it does not immediately start executing its code. Instead, it returns a generator object. The generator object has a next() method that can be used to resume the execution of the generator function.
Generators are useful for a variety of tasks, such as:
Here is an example of a generator function:
// declare a generator
function* generateNumbers() {
for (let i = 0; i < 10; i++) {
yield i;
}
}
//using the generator
const generator = generateNumbers();
for (let value of generator) {
console.log(value);
}
The * after the function keyword in the example is used to tell the JavaScript engine that generateNumbers() is a generator function. Without the *, the JavaScript engine would treat the function as a regular function.
This function will generate a sequence of 10 numbers, starting from 0. The yield keyword is used to pause the execution of the function and return the current value. The next() method is then used to resume the execution of the function and get the next value.
const generator = generateNumbers();
// The first call to next() will return the value 0.
const value1 = generator.next().value;
console.log(value1); // 0
// The second call to next() will return the value 1.
const value2 = generator.next().value;
console.log(value2); // 1
// The third call to next() will return the value 2.
const value3 = generator.next().value;
console.log(value3); // 2
Generators are a powerful tool that can be used to simplify and improve the performance of JavaScript code. If you are not familiar with generators, I encourage you to learn more about them. They can be a valuable asset in your JavaScript toolbox.
For more information on generators in JavaScript, please see the following resources:
Java function can be executed in syncrhon or asynchronous mode. First mode is the default mode and is used in single thread applications. Asynchronous mode is used to create multi-thread applications in JavaScript.
There are two main types of asynchronous code style you'll come across in JavaScript code, old-style callbacks and newer promise-style code.In the below sections we'll review each of these in turn.
Async callbacks are functions that are specified as arguments when calling another functionwhich will execute code in the background. When the background code finishes running, it calls the callback function to let you know the work is done.
Demo: We have preloaded source file: "async-demo.js" containing a callback function. This load a resource via the XMLHttpRequest API that is called from a wrapper. You can open the console (F12), select "source" tab, and investigate the source file (call_back.js).Let's preview the code before we execute this demo:
/* async-demo.js content */
function loadAsset(url, type, callback) {
let xhr = new XMLHttpRequest();
// fetch the image from URL
xhr.open('GET', url);
xhr.responseType = type;
// hook up the callback function
xhr.onload = function() {
callback(xhr.response);
};
xhr.send();
}
// function wrapper that interact with DOM
function displayImage(blob) {
let objectURL = URL.createObjectURL(blob);
let image = document.createElement('img');
image.src = objectURL;
// find the target div that is display below
const target = document.querySelector('#load-async-demo');
target.appendChild(image);
}
We can call this function: displayImage() using a JavaScript link that looks like this:
<a href="javascript:loadAsset('img/tezaur.jpg', 'blob', displayImage)">discover</a>
Note: Method xhr.open() belongs to object xhr of type XMLHttpRequest.We have not created this function ourselves but we have used it. Next we will learn how to create new asynchronous functions.
Let's find the ancient tresure using this link: discover
This is the secret. A promise lets asynchronous methods to return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise.It will eventually supply the result value at some point in the future.
A promise can have one of 3 states:
A pending promise can either be fulfilled with a value or rejected with an error. When either of these options happens, the associated handlers queued then() are called one by one. Sometimes the promise has already been fulfilled or rejected when a corresponding handler is attached.In this case, the handler will be called immediately
A Promise has methods used to associate callback action with a promise that becomes settled.
Method Resut: Promise methods return a newly generated promise object, which can optionally be used for chaining multiple promises. We will explain chain promises using a pseudocode.Let's investigate this workflow diagram:
Promise Fulfillment
In next pseudo-code example we chain one promise with 3 other downstream promises and one final catch handler.
/* chained promises */
const myPromise =
(new Promise(myExecutorFunc))
.then(handleFulfilledA)
.then(handleFulfilledB)
.then(handleFulfilledC)
.catch(handleRejectedAny);
Example:
In this example, we use setTimeout() to simulate a process. In reality, you will probably be using something like XHR or an HTML5 API,that may take a long time to execute. You can copy/paste this example in console to verify.
// create an empty promise
let myFirstPromise = new Promise((resolve, reject) => {
setTimeout( function() {
resolve("timer stop!") // Yay! Everything went well!
}, 5000)
})
//control message
console.log("timer start: wait for it ...")
//wait for promise to execute
myFirstPromise.then((successMessage) => {
console.log("Done! " + successMessage)
});
Learn more about promises here: MDN Promises
So far we have learned how to create a Promise, that is an Object. It is a bit inconvenient to use. We have a pair of keywords in JavaScript that enable creation of Asynchronous functions or expressions.These can be used to create parallel threads.
Syntax:
async function name([param[, param[, ...param]]]) {
//statements
[await n]
}
Example:
/* this function return a promise */
function resolveAfterNSeconds(n) {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved in:'+n+'s');
}, 1000*n);
});
}
/* asynchronous function resolve a promise */
async function asyncCall(x) {
console.log('calling');
const result = await resolveAfterNSeconds(x);
console.log(result); // expected output: "resolved"
}
/* various calls that execute in parallel */
asyncCall(25); //25 seconds
asyncCall(10); //10 seconds
asyncCall(5); //5 seconds
asyncCall(30); //30 seconds
Homework: If you copy/paste previous program in console, you will see first messages when each timer expire. First of course is: resolve:5 andtotal time of execution is 30 seconds.That proves asynchronous functions are executed in parallel.You can invoke the function manually while the promises are pending (console is not blocked).
Output:
resolved in:5s
resolved in:10s
resolved in:25s
resolved in:30s
Read next: Control Flow