JavaScript: Advanced
Page 7
Template Literals, Promises, Closures, Arrow Functions
Introduction
Learn many new or advanced JavaScript techniques including template literals, template literals with expressions, promises, closures, arrow functions, rest parameters, strict mode, modules including simple imports with exports, and class imports with exports. We'll also combine rest parameters with arrow functions.
Template Literals
Template Literal Substitution
A template literal with substitution
allows developers to substitute variable values within brackets.
A template bracket begins with ${
and ends with }
.
Insert strings sBreed
and sType
into the string text
,
within brackets ${..}
.
The return value equals Animal: Savannah, Cat.
.
Click
the box to see the result, below.
The following function, fTemplate()
includes the code to return a string
from a template literal.
function fTemplate(){ let sBreed = "Savannah"; let sType = "Cat"; let text = `Animal: ${sBreed}, ${sType}.`; return text; }
Template Literal Expression
A template literal with an expression
allows an expression within a template.
The template begins with ${
and ends with }
.
The expression (start * growth).toFixed(2)
evaluates between the brackets ${...}
.
The result should display Final: 27.50
.
Click
a box to see the result, below.
The following function includes the code
to return a string from a template literal
with an expression.
function fTempExp(){ let start = 22; let growth = 1.25; let final = `Final: ${(start * growth).toFixed(2)}`; return final; }
Click a Box
Template Literal Substitution
function fTemplate(){ let sBreed = "Savannah"; let sType = "Cat"; let text = `Animal: ${sBreed}, ${sType}.`; return text; }
Template Literal Expression
function fTempExp(){ let start = 22; let growth = 1.25; let final = `Final: ${(start * growth).toFixed(2)}`; return final; }
Closures
Declare a closure as a child function within a parent function. The child function retains access to properties in the parent scope.
Simple Factorial
Call factorial() the number of times
you want to calculate a factorial, starting at one.
The factorial from one to four
should equal 1 * 2 * 3 * 4 = 24
.
The following code displays
a simple method to process the factorial of four.
The last statement, this.innerHTML = factorial();
is the fourth call to factorial()
and displays the result in an HTML element.
factorial(); factorial(); factorial(); this.innerHTML = factorial();
Simple Factorial Closure
Tap a box below to see closure examples in action. The simple factorial closure source code displays below.
/** * Factorial equals the * product of a series of numbers. * 1 * 2 * 3 * 4... */ const factorial = (function () { let f = 1; let r = 1; // The closure: return function () { console.log("f: "+f+ ", r:"+r); console.log("f * r: " +f * r); r = f * r; f += 1; return r; } } )();
Factorial with End Value Parameter
A slightly simpler closure includes
a parameter which indicates the factorial end point.
For example if you want to see the
factorial of seven, call factorialN(7);
.
Pass a parameter to the factorial
function. The parameter indicates
the last number in a series of products.
For example if you call factorialN(4)
,
the result should equal 1 * 2 * 3 * 4 = 24
.
Tap a box below to see both closure examples in action. The code below demonstrates one technique to use a closure to process factorials. However closures have many more uses.
/** * Factorial equals the * product of a series of numbers. * 1 * 2 * 3 * 4 * @param n: Number representing * end of factorial calculation. */ const factorialN = (function (n) { let f = 1; let r = 1; return function (n) { for (var i = 0; i < n; i++){ console.log("f: "+f+ ", r:"+r); console.log("f * r: " +f * r); r = f * r; f += 1; } return r; } }
Tap the Box
Call factorial from one to four. Should equal 24.
Enter Factorial Digit Below:
Promises
Promises link long running code with result handler functions, which wait for a response.
- Producer
- Code that takes time.
- Consumer
- Code that waits for result.
- Promise
- Link between Consumer and Producer
Order
First define your promise handler or handlers. Second create a Promise object. Third call the promise.
- Define Promise Handler;
displayInfo()
. - Create Promise object;
var promiseButton = new Promise(...)
- Call Promise;
promiseButton.then(...)
Promise Handler
Define a promise handler that simply displays the result. This handler can be used if the Promise results in an error, or acceptable responses.
function displayInfo(sInfo){ let eDebug = document.getElementById('eDebug'); eDebug.innerHTML = sInfo; }
Create a Promise
The following code creates a Promise with status handlers for either an error or acceptable responses.
This promise handler
calls an XMLHttpRequest()
to download an XML file.
/** * New Promise object * Inline function * declared in parameter list. */ var promiseButton = new Promise( // Inline function // in parameter list. // Two function names passed // as parameters within // inline function. function(resolveOK, resolveError) { // Open HTTP request: let req = new XMLHttpRequest(); // Obtain ss-promise-got.html: req.open('GET', "assets/ss-promise-got.html" ); // Attempt to load // ss-promise-got.html: req.onload = function() { if (req.status == 200) { // Download went well. // Call function in // parameter list. resolveOK(req.response); } else { // Download error. // Call second function // in parameter list. rejectError("File not Found"); } }; // Execute the download: req.send(); });
Call a Promise
Call the promise, with the actual
functions replace formal parameters
for
resolveOK()
and resolveError()
functions
with the actual parameter displayInfo()
.
Place parameter functions
in the order they're declared
with promiseButton = new Promise(...)
.
The following function, promiseCall()
responds when the user taps a button.
function promiseCall(){ promiseButton.then( function(value) {displayInfo(value);}, function(error) {displayInfo(error);} ) }
The following HTML markup
executes promiseCall()
when the user taps the div element.
<div id="eDebug" onclick="promiseCall()" > </div>
Tap for Promise
The button below calls a function
which activates promiseButton.then(...)
.
I created the promiseButton
, outside of
the calling function, with a var instead of let.
That allowed me to define the promise
earlier, and allows the function to access the promise.
Tap the Button!
Arrow Functions
Arrow functions have a unique signature, and different parent element, than normal JavaScript functions. Signature pseudo code, for an arrow function, follows.
functionName = (parameters) => function body;
You can remove brackets and the return a value
to functionName
,
for functions with only one statement
and a return value.
The following two function definitions demonstrate how to accomplish the same task with either a normal function or an arrow function.
Return the value after operator =>
.
// Normal function: fHi = function() { return "Hi Web Developer!"; } // Arrow function: fHi = () => "Hi Web Developer!";
The following two examples demonstrate arrow functions with parameters.
// Normal function: function fMultiply(a,b){ return a * b; } // Arrow function: let fMultiply = (a, b) => a * b;
Normally the this
property
is the object that calls a function, such
as a button.
With arrow functions this
property is the function's owner, in this case the
owner is the window.
// Normal fNormal = function() { btnNormalTxt = document.getElementById("btnNormalTxt"); btnNormalTxt.innerHTML = this; } document.getElementById("btnNormal").addEventListener( "click", fNormal ); // Arrow fArrow = () => { btnArrowTxt = document.getElementById("btnArrowTxt"); btnArrowTxt.innerHTML = this; } document.getElementById("btnArrow").addEventListener( "click", fArrow );
Tap Both Buttons
The small text, toward the bottom of each button,
tells you which type of object this
represents.
Rest Parameters
Rest parameters allow JavaScript variadic functions.
When the function's defined, include
a rest parameter, preceded by three dots,
such as f(...restParam);
.
You may treat the rest parameter
as an array.
A variadic function includes a variable number of parameters. Developers can modify the number of parameters when the function's called.
Rest parameters are also called spread operators.
Rest Example
For example, the following function, fRest()
,
displays the first two parameters, p1
and p2
, with the last parameter,
aryMore
.
Tap the red box
to see the results.
Notice the parameter, ...aryMore
,
displays as an array.
See the HTML Simple Rest Markup.
function fRest(p1, p2, ...aryMore) { let eRest = document.getElementById('idRest'); eRest.innerHTML = "p1: "+p1+"<br>p2:"+p2+"<br>aryMore:"+aryMore+","; }
Simple Rest Markup
Function fRest()
displays
the first two parameters, Greyhound, Poodle
as unique values.
The last three parameters,
Boxer, Chihauhau, Shepherd
,
display as the contents of an array.
<div class="box rd" id="idRest" onclick="fRest( 'Greyhound', 'Poodle', 'Boxer', 'Chihuahua', 'Shepherd' )"; > Tap to call fRest() </div>
Rest Buttons
Tap to call fRest()
Tap to call fReduce()
Combine Arrow, Rest Parameter, Array Reduce
This section applies the Array reduce()
method, with an arrow function
on a rest parameter.
Function: Arrow with Reduce Array
The reduce()
array method iterates
over an array.
Method reduce()
applies the result of each previous call to
the current call of a developer defined function.
The end result is one value.
The first parameter to reduce()
is a developer defined function.
The second, optional, parameter
is the starting value for the developer defined function.
The following code defines a function for reduce()
that multiplies the sequence of values in an array.
Tap the
green box
to see the results of the fReduce()
function, below.
// Arrow function // Multiplies a series // of numbers in an array. const fReduceMultiply = (prev, curr) => prev * curr; function fReduce(){ // Obtain the button. let eReduce = document.getElementById('idReduce'); // Declare an array. let aryOneToFour = [1, 2, 3, 4]; // 1 * 2 * 3 * 4 = 24. eReduce.innerHTML = aryOneToFour.reduce(fReduceMultiply)); eReduce.innerHTML += "<br >"; // 5 * 1 * 2 * 3 * 4 = 120. // Call fReduce with an initial value of five. eReduce.innerHTML += aryOneToFour.reduce(fReduceMultiply, 5)); }
Order With Rest Array
Only one rest parameter is allowed per function and that rest parameter must be the last or only parameter. As you saw earlier, functions accept individual parameters passed before the rest array.
Order with Reduce Method
With array's reduce()
method,
the first parameter is an array, however
the last parameter can provide the initial
value to apply for reduce.
Rest Versus Reduce
Functions with Rest parameters require
the Rest (array) parameter last
and optional other parameters first.
The array reduce()
method
requires the array parameter first
and optional initial value last.
After some testing it appears that
developers might not be able to pass
non Rest parameters to the reduce()
method. However perhaps that
depends on the current browser's JavaScript version..
Product Arrow Function: Rest Parameter
Now create a function with a rest parameter
then apply the reduce function defined previously,
named fReduceMultiply()
.
The following simple function
iterates over every value in
rest parameter (array), ...aryArgs
,
multiplying each value by the preceding value.
The product is returned.
/** * Multiply every value in ...aryArgs. * @param Rest or spread parameter: ...aryArgs * @returns: product of array values. */ function fMult(...aryArgs) { return aryArgs.reduce(fReduceMultiply); }
Markup: Rest, Multiply, Arrow
<div class="box y" onclick="this.innerHTML = fMult(1,2,3,4)" > Tap to Multiply:<br> (1,2,3,4) </div>
Sum Arrow Function: Rest Parameter
Implement a function with a rest parameter. Define and call an arrow function to sum every value in the rest parameter's array. Return the sum.
/** * Sum every value in ...aryArgs. * @param Rest or spread parameter: ...aryArgs * @returns: sum of array values. */ function fSum(...aryArgs) { return aryArgs.reduce((previous, current) => { return previous + current; }); }
Markup: Rest, Sum, Arrow
The following markup declares
a box. Click on the box
to see the sum of the rest parameter,
1,3,4,5
.
Try It: Rest, Arrow: Sum & Product.
<div class="box vi" onclick="this.innerHTML = fSum(1,2,3,4)" > Tap to Sum:<br> (1,2,3,4) </div>
Try It: Rest, Arrow: Sum & Product
Tap to Multiply:
(1,2,3,4)Tap to Sum:
(1,2,3,4)Strict Mode
Strict mode was enabled in ECMAScript 5. Most browsers now support strict mode, yet older browsers ignore the simple string declaration. Strict mode throws an exception when the developer violates good practices, such as attempting to write to an undeclared variable, undeclared object, undeclared property or getter only property. Strict mode throws exceptions with many other violations of good practice, or use of reserved keywords, in preparation for future JavaScript versions. See the following lists for examples.
Strict Mode Errors
The following list includes examples which will throw an exception in strict mode.
- Assign to Non Declared Variable
- notStrict = "Throws an Error.";
- Assign to Non Declared Object
- myObject = {x:256,y:512}
- Deleting a Variable
- var firstName = "Doris"; delete firstName;
- Deleting a function
- function f(){ var x = 20;} delete f;
- Duplicate Parameters
- function f(x,x){var y = 0;}
- Octal Literals
- Use character
o
after zero. Use var y = 0o256;, rather than var y = 0256; - Octal Escape Characters
- Use hexadecimal escape sequences,
\x45
, not octal escape sequences,\105
. - Write to Read Only Property
- var obj = {};
Object.defineProperty(obj, 'name', { value: 'Doris', writable: false });
obj.name = 'Tony'; - Write to Get Only Property
- var obj ={get v(){return "v";}; obj.v = "a";
Reserved Keywords or Expressions
This list provides a clue as to which features W3C plans to implement in the future. For example perhaps access modifiers private, protected and public are on their way.
Don't use the following words as variables, functions or expressions, in strict mode.
- eval
- arguments
- with
- eval("let s = 'Amy'");
- implements
- interface
- let
- package
- private
- protected
- public
- static
- yield
this Property
In strict mode, the keyword this
returns either the
object that calls a function or undefined
.
In normal mode, the keyword this
returns
either the the object that calls a function
or the window.
Apply Strict Mode
If you want JavaScript to run in strict mode
then place the line, use strict
;, at
the top of a file.
Strict mode then applies to the entire file. It's global.
If you want a function only, to run in strict mode,
then place, use strict
;, as the
first line in a function.
The following function throws an exception
because variable i
is not declared before it's used.
function fStrictModeBad(){ "use strict"; // Throws an exception: i = 3; }
The following function should execute fine.
function fStrictModeOK(){ "use strict"; let i = 3; }
Tap to Execute Bad Function:
function fStrictModeBad(){ "use strict"; try{ // Throws an error i = 3; return i; } catch(ex){ return ex.toString(); } }
Tap to Execute OK function:
function fStrictModeOK(){ "use strict"; try{ let i = 3; return i; } catch(ex){ return ex.toString(); } }
Modules
Modules allow developers to implement shared functionality while also protecting functions, methods and properties.
Simple Module Export
Modules are simply files which enable
sharing of functions, methods and properties.
However you can't externally modify those
functions, methods and properties.
Use the keywords export
and import
to access features declared in one file, from another file.
Module to Export
Create a file for modules.
Let's call it export-first-header.js
.
This file will import from the header, so we
want it simple.
Apply the export
keyword to function popupMessage()
See JavaScript file
export-first-header.js.
For example create the following
exportable function in export-first-header.js
.
The function displays a
string in the alert dialog.
/** * Display an alert with a message. * @param sMessage: String */ export function popupMessage(sMessage) { alert(sMessage); }
Simple Module Import
Imports allow developers to load read-only modules of JavaScript, for use in their own files. Imports automatically load in strict mode.
Imports require CORS. Optionally copy pages and files to the same Web server.
Module Scope
Scripts loaded as a module are scoped to the script itself. That makes access within or without the script a challenge. Some people suggest adding the module to the window object. That doesn't seem like good practice, but it might work best for your situation.
The following inline script imports
everything exported from export-first-header.js
to m
.
The script's imported as a module
, within
the header of JavaScript: Simple Module Example.
As after the file loads, you'll see an
alert which displays the text, First Module
.
<script type="module" > import * as m from './javascript/export-first-header.js'; // Use the exported function // from export-first-heaader.js: m.popupMessage('First Module'); </script>
Try Import & Export
See JavaScript: Simple Module Example. Later tap the Simple Module button, here to see a simple onclick event listener with modules.
Class: Module, Import, Event Listener
This section demonstrates how to create a class module for import and export. Classes obviously enable many web development possibilities. Here we'll just focus on an onclick event listener. You'll import the module then assign a module method as a click event listener, to a button.
Many online questions revolve around finding a simple solution to assign a straight forward JavaScript import, as an event listener. Here's one relatively simple example. You'll see the other, even simpler, technique with the Simple Module button.
Export Class
The following export module file,
export-class.js,
declares a class with two static functions.
The first static function,
fLog()
, prints out to the
console, for debugging purposes.
The second static function, fBtnText()
,
changes the text on our button.
The last line declares that this class is
for exporting, with export { expClass }
.
The entire JavaScript follows.
class expClass { /** * Log the function name, * and parameter value. * @param val: String */ static fLog = function(val) { // The class and function: console.log('expClass.fLog()'); // Name of parameter: console.log('log:'); // Value of parameter. console.log(val); }; /** * Change text on * button when it's tapped. * * Note this example expects * your button to include an * element with the ID 'btnText'. */ static fBtnText = function() { // Get the button's main text area: let btnTxt = document.getElementById('btnTxt'); // Let user know, button clicked: btnTxt.innerHTML = "Button Tapped!"; // Move to the button text: window.location="#btnTxt"; }; }; export { expClass }
Module: Import Our Class
Import modules, in the header,
with the attribute type
assigned the value module
.
Obtain our button by ID, btnMod
.
Assign the expClass
static method,
fBtnText
,
to the button's onclick
event listener.
View or download the JavaScript file,
export-class.js.
View or download the JavaScript file,
import-class.js.
Tap the
Class Module button,
and its text changes.
The click event listener, from our module,
fBtnText()
activates.
Include Module: in Header or External File
you can include your import module within the header, or inline. Optionally you can include your import module as an external file. The following listing demonstrates adding a module to the header, or inline.
<script type="module" > // Import the class: import {expClass} from './javascript/export-class.js'; // Call the logging function. // Look in your console log: expClass.fLog('Test Logging: Export Class'); // Obtain our button. btnMod = document.getElementById( 'btnModClass' ); if(btnMod != null){ // Add the on click listener: btnMod.addEventListener( 'click', expClass.fBtnText, false ); // Log that we have this button: console.log(btnMod); } </script>
The following listing demonstrates adding import-class.js externally from a JavaScript file.
<script async type="module" src="javascript/import-class.js"> </script>
Tap a Module Button!
The following two buttons respond
to module event listeners.
the Simple Module
button activates
function popupMessage()
,
declared in
export-first.js.
The Class Module
button activates
method fBtnText()
declared in file
export-class.js.
Button Markup
HTML markup for the button displays below.
<button class="btn" id="btnModSimple" title="Module Simple"> <span class="txt" > Simple Module </span> </button> <button class="btn" id="btnModClass" title="Class Module"> <span class="txt" id="btnTxt" > Class Module </span> </button>
Summary
You learned many new or advanced JavaScript techniques including template literals, template literals with expressions, promises, closures, arrow functions, rest parameters, strict mode, modules including simple imports with exports, and class imports with exports. We also combined rest parameters with arrow functions.
See the JavaScript advanced.js source file for everything, except modules, on this page.
Module Code
See simple module Javascript files export-first.js with import-first.js and more complex class modules with export-class.js and import-class.js.
Learn JavaScript
JavaScript's the foundation of Web developer and Website design skills. This free and unique JavaScript tutorial includes some new or seldom used, but useful features.