JavaScript Topics
Introduction
Learn some advanced JavaScript techniques including template literals, template literals with expressions, promises, closures, arrow functions, rest parameters, strict mode, imports and modules. 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
let sBreed = "Savannah";
let sType = "Cat";
let text = `Animal: ${sBreed}, ${sType}.`;
return text;
}
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
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.
var promiseButton = new Promise( function(resolveOK, resolveError) { let req = new XMLHttpRequest(); req.open('GET', "assets/ss-promise-got.html" ); req.onload = function() { if (req.status == 200) { // Download went well. resolveOK(req.response); } else { // Download error: rejectError("File not Found"); } }; // Execute the download: req.send(); });
Call a Promise
Call the promise, with the
resolveOK()
and resolveError()
functions
in order.
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.
Requires CORS
Either enable CORS or copy files
to a Web server. Otherwise
the promise won't download the file, assets/ss-promise-got.html
.
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 keyword 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.
// Before fHi = function() { return "Hi Web Developer!"; } // Arrow fHi = () => "Hi Web Developer!";
The following two examples demonstrate arrow functions with parameters.
// Before function fMultiply(a,b){ return a * b; } // Arrow 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" id="idRest" style="background-color:red;" onclick="fRest( 'Greyhound', 'Poodle', 'Boxer', 'Chihuahua', 'Shepherd' )"; > Tap to call fRest() </div>
Rest Buttons
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" style="background-color:yellow; color:black;" 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" style="background-color:violet" onclick="this.innerHTML = fSum(1,2,3,4)" > Tap to Sum:<br> (1,2,3,4) </div>
Try It: Rest, Arrow: Sum & Product
(1,2,3,4)
(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
- Don't use
var y = 0256;
Use charactero
after zero. Usevar y = 0o256;
. - 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(...);
- 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.
function fStrictMode(){ "use strict"; // Throws an exception: i = 0; }
Simple Module
Modules are simply files which enable
sharing of functions, methods and properties.
Use the keywords export
and import
to access features from one file to another file.
Create a file for modules, let's call it module-test.js
.
Apply the export
keyword to specified
functions, methods and properties.
Those functions, methods and properties, will
then be available outside of module-test.js
.
For example create the following
exportable function in module-test.js
The function displays a
string in the alert dialog.
/** * Display an alert with a message. * @param sMessage: String */ export function popupMessage(sMessage) { alert('Popup Message: '+sMessage+'!'); }
Simple 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. I've seen suggestions to add the module to the window object. That doesn't seem like a good practice, but it might work best for your situation.
The following script imports
everything exported from module-test.js
to m
.
As soon as it load's, you'll see the
alert with Hello World
.
You can view or download the JavaScript,
module-test.js.
<script type="module"> import * as m from './javascript/module-test.js'; // Use exported values // from module-test here. m.popupMessage('Hello World!'); </script>
Module, Import, Event Listener
This section demonstrates how to create a class module for export. Import the module and assign a module method as a click event listener, to a button.
I noticed many people online seemed to be looking for a simple solution to assign a straight forward JavaScript import, as an event listener. Here's one relatively simple example.
The following export module file, export-class.js, declares a class with two static functions. The first static function prints out to the console, for debugging purposes. The second static function 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('val'); // Value of parameter. console.log(val); }; /** * Change text on * button when button tapped. */ 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 with the attribute type
and 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. When you're done, tap the module button, and its text changes.
<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 log'); // Obtain our button. btnMod = document.getElementById( 'btnMod' ); if(btnMod != null){ // Add the on click listener: btnMod.addEventListener( 'click', expClass.fBtnText, false ); // Log that we have this button: console.log(btnMod); } </script>
Tap the Button!
Button Markup
HTML markup for the button displays below.
<button class="btn" id="btnMod" title="Test Module" > <span class="txt" id="btnTxt" > Test Module </span> </button>
Summary
You learned some advanced JavaScript techniques including template literals, template literals with expressions, promises, closures, arrow functions, rest parameters, strict mode, imports and modules. We also covered how to combine rest parameters with arrow functions.
See the JavaScript advanced.js source file for this page. See the module JavaScript files, module-test.js and export-class.js.