Javascript Coding Book For Beginners Web Development Crash Course Head First Javascript Programming Book For Modern Software Engineering Javascript The Definitive Guide For Coding Interview
Javascript Coding Book For Beginners Web Development Crash Course Head First Javascript Programming Book For Modern Software Engineering Javascript The Definitive Guide For Coding Interview
Neo D. Truman
Copyright
Copyright
Table of Contents
Preface
Book Audience
How to Contact Us
Conventions Used in This Book
CHAPTER 1 Setting Up a Development Environment
1.1 Installing a Code Editor
1.1.1 Install Essential Extensions
1.1.2 Installing Live Server
1.1.3 Enable Formatting Code on Save
1.1.4 Disable Compact Folders
1.1.5 Enable Word Wrap
1.1.6 Set Tab Size Smaller
1.2 Using a Web Browser
1.2.1 Using Developer Tools in The Browser
1.2.2 Using Console Tool
1.2.3 Using Source Tool
1.3 Preparing a Workspace
CHAPTER 2 Introduction to JavaScript
2.1 Text of The JavaScript Code
2.2 JavaScript Comments
2.2.1 Single-line Comments
2.2.2 Multi-line Comments
2.3 Identifiers
2.4 Reserved Words
2.5 Semicolons
2.6 Using Strict Mode
2.6.1 Declaring Strict Mode
2.6.2 What Are Not Allowed in Strict Mode?
2.6.3 The this Keyword in Strict Mode
2.7 JavaScript Modules
CHAPTER 3 Types, Values, and Variables
3.1 Variable Declaration
3.1.1 Declarations with Keywords
3.1.2 Variable Scope
3.2 Primitive Data Types
3.2.1 undefined
3.2.2 null
3.2.3 String
3.2.3.1 Creating Strings
3.2.3.2 Working with Strings
3.2.3.3 Regular Expressions
3.2.3.4 Template Literals
3.2.3.5 Escape Sequences
3.2.4 Number
3.2.4.1 Creating Numbers
3.2.4.2 Strings and Numbers
3.2.4.3 Arithmetic in JavaScript
3.2.4.4 Not a Number
3.2.4.5 Infinity
3.2.5 BigInt
3.2.6 Boolean
3.2.7 Symbol
3.3 Object
3.3.1 Creating Objects
3.3.2 Object.assign()
3.3.3 Accessor Properties
3.3.4 Global Object
3.3.5 Upgrading Object Literal
3.3.5.1 Shorthand Properties
3.3.5.2 Shorthand Methods
3.3.5.3 Computing Property Keys
The first step in setting up your development environment is choosing your code
editor. Almost editors have essential features like autocompletion, syntax
highlighting, formatting code, and smart refactoring. Using them helps you to
prevent potential mistakes. Other features such as line-by-line debugging could
be already available in the editor. However, we will use the Developer Tools of
web browsers while debugging JavaScript code. When finished setting up the
development environment, your coding will be amazingly easy and fast.
There are several tools you might consider so that you could
always choose any of them. No matter what tools you choose,
you’ll follow a similar process to learn the lessons.
1.1 Installing a Code Editor
In this book, we’ll use Visual Studio Code (shortened to VS Code) as the
code editor. You can download this free at
https://code.visualstudio.com/download
I chose VS Code because it was ranked as the most popular code editor
across languages on Stack Overflow.
You could see the errors that occur in your web page and the debugging
messages here. The Console panel is the one that shows the messages you output
with console.log() and any unhandled errors.
1.2.3 Using Source Tool
You may have to select the Sources tab in order to open the debugging tool.
It supports line-by-line debugging with breakpoints, reviewing the call stack, etc.
The details will be introduced with code later.
1.3 Preparing a Workspace
Please follow these steps to create your workspace:
● Create the Example folder, such as “D:\Example”
● Open the Visual Studio Code
● In the VS Code, select menu File > Open Folder…
● Select your folder, “D:\Example” in my example
● Hover mouse on the EXAMPLE folder, some icons will appear as
below.
<body>
<h2>Testing Page</h2>
<!-- Your HTML code here -->
<script src="./app.js"></script>
</body>
</html>
● Select menu File > Save in order to save change to the index.html file.
● Hover mouse on the EXAMPLE folder and click the New File icon.
● Type “app.js” and press Enter.
● Then type below JavaScript code into the editor.
"use strict";
console.log('This is your first JS code.');
● Select menu File > Save in order to save change to the app.js file.
You will change JavaScript code in the app.js file and HTML
code in the index.html file while learning this book.
Let’s try the code in a web browser, such as Google Chrome. You should
configure Google Chrome as your default web browser before doing the
following steps.
Right click on the index.html file from Explorer Window and click on Open
with Live Server.
This will launch a local web server with live reload feature for the file
index.html.
We could try to change our HTML code a little bit and save the index.html
file. Consequently, the web page will automatically load the change for us as this
screenshot.
Then, open the Console panel to see the debugging log.
CHAPTER 2
Introduction to JavaScript
function myFunction() {
"use strict";
y = 20; // ReferenceError: y is not defined
}
myFunction();
2.6.2 What Are Not Allowed in Strict Mode?
Using a variable without declaring it will cause a Reference Error (… is not
defined).
Example:
"use strict";
x = 10; // ReferenceError: x is not defined
Deleting a variable (or function) will cause a Syntax Error (delete of an
unqualified identifier in strict mode).
Example:
"use strict";
let x = 10;
delete x; // SyntaxError: Delete of an unqualified identifier in strict mode
function myFunc() { };
delete myFunc; // SyntaxError: Delete of an unqualified identifier in strict
mode
Duplicating a parameter name will cause a Syntax Error (Duplicate parameter
name not allowed in this context).
Example:
"use strict";
function myFunc(p1, p1) { }; // SyntaxError: Duplicate parameter name not
allowed in this context
Writing to a read-only property will cause a Type Error (cannot assign to
read-only property).
Example:
"use strict";
const obj = {};
Object.defineProperty(obj, "x", { value: 10, writable: false });
obj.x = 20; // TypeError: Cannot assign to read only property 'x' of object
Writing to a get-only property will cause a Type Error (cannot set property
which has only a getter).
Example:
"use strict";
const obj = { get x() { return 10 } };
obj.x = 20; // TypeError: Cannot set property x of Object which has only a
getter
For security reasons, eval() is not allowed to create variables in the scope
from which it was called.
Example:
"use strict"
eval("let x = 10");
console.log(x); // ReferenceError: x is not defined
2.6.3 The this Keyword in Strict Mode
In Strict Mode, the this keyword refers to the object that called the function.
If the object is not specified, functions in Strict Mode will return undefined .
Example:
"use strict";
function myFunction() {
console.log(this); // will print "undefined"
}
myFunction();
console.log(doLog);
doLog('A message');
doLog('Another message', LOG_TYPE);
doLog('A warning message', WARN_TYPE);
doLog('An error message', ERROR_TYPE);
logger.js
export const LOG_TYPE = 'log';
export const WARN_TYPE = 'warn';
export const ERROR_TYPE = 'error';
function doLog(message, logType = LOG_TYPE) {
console[logType](message);
}
export default doLog;
console.log(doLog);
doLog('A message');
doLog('Another message', CONSTANTS.LOG_TYPE);
doLog('A warning message', CONSTANTS.WARN_TYPE);
doLog('An error message', CONSTANTS.ERROR_TYPE);
console.log(CONSTANTS.DEFAULT_CONSTANT); // undefined
console.log(CONSTANTS.default); // 'default constant'
console.log(doLog);
doLog('A message');
doLog('Another message', CONSTANTS.LOG_TYPE);
doLog('A warning message', CONSTANTS.WARN_TYPE);
doLog('An error message', CONSTANTS.ERROR_TYPE);
console.log(sum(10, 20)); // 30
Example 3b:
index.html, constants.js, logger.js, and app.js are as same as example 3a.
helper.js
export { default } from './logger.js'; // export default
console.log(newLog);
newLog('A message');
newLog('Another message', CONSTANTS.LOG_TYPE);
newLog('A warning message', CONSTANTS.WARN_TYPE);
newLog('An error message', CONSTANTS.ERROR_TYPE);
console.log(sum(10, 20));
CHAPTER 3
Types, Values, and Variables
function test() {
var y = 20;
}
console.log(y); // ReferenceError: y is not defined
Variables declared with let or const have block scope. It means that the
variables are available only within a pair of curly brackets {} . Otherwise, it is
available to any other code in the current document (global scope).
Example:
"use strict";
if (true) {
let x = 10;
}
console.log(x); // ReferenceError: x is not defined
3.2 Primitive Data Types
In JavaScript, a primitive is data that is not an object and has no methods.
There are 7 primitive data types:
● string
● number
● bigint
● boolean
● undefined
● null
● symbol
function test(y) {
console.log(typeof y);
console.log("y =", y)
}
test(); // invoke the function with no argument
// undefined
// "y = undefined"
3.2.2 null
In computer programming, a null value represents a reference that points to
a nonexistent or invalid object or address. The value null represents the
intentional absence of any object value.
In JavaScript, every object is derived from null value, and therefore typeof
operator returns object for it.
Example:
"use strict";
let x = null;
console.log(typeof x); // object
console.log("x =", x) // "x = null"
x = x + 10;
console.log("x =", x) // "x = 10"
let r01 = x + y + z;
// x + y returns 30 (number)
// then 30 + "30" (z) returns "3030"
console.log(typeof r01); // string
console.log(r01); // "3030"
let r02 = z + y + x;
// z + y return "3020" (string)
// then "3020" + 10 (x) returns "302010"
console.log(typeof r02); // string
console.log(r02); // "302010"
JavaScript will try to convert strings to numbers in all numeric operations
since the result cannot be a string. This is type coercion in JavaScript.
"use strict";
let x = "20";
let y = "10";
let r01 = x - y;
console.log(typeof r01); // number
console.log(r01); // 10
let r02 = x * y;
console.log(typeof r02); // number
console.log(r02); // 200
let r03 = x / y;
console.log(typeof r03); // number
console.log(r03); // 2
The + operator will concatenate strings and return a string as
the result.
3.2.4.5 Infinity
Infinity is a property of the global object. The initial value of Infinity is
Number.POSITIVE_INFINITY . The value Infinity (positive infinity) is greater
than any other number.
"use strict";
console.log(1 / Infinity); // 0
console.log(1 / 0); // Infinity
3.2.5 BigInt
The bigint type is a numeric primitive in JavaScript that can represent
integers with arbitrary precision. With bigint , you can safely store and operate
on large integers even beyond the safe integer limit for Number .
function test() {
console.log("Hi");
}
window.test(); // "Hi" (the same as invoking test())
3.3.5 Upgrading Object Literal
3.3.5.1 Shorthand Properties
We can use variables to define object’s properties. And in case that the
property name is same as name of the variable, we can use the shorthand form as
below.
"use strict";
let firstName = 'Neo';
let lastName = 'D. Truman';
let user = {
firstName,
lastName,
email: "neodtruman@gmail.com"
}
console.log(user);
// {
// firstName: 'Neo',
// lastName: 'D. Truman',
// email: 'neodtruman@gmail.com'
// }
3.4.8.2 fill()
The fill() method changes all elements in an array to a static value , from a
start index (default 0) to an end index (default array.length ). It returns the
modified array.
fill(value, start, end)
Example:
"use strict";
[1, 2, 3, 4, 5].fill(6); // [6, 6, 6, 6, 6]
[1, 2, 3, 4, 5].fill(6, 2); // [1, 2, 6, 6, 6]
[1, 2, 3, 4, 5].fill(6, 2, 4); // [1, 2, 6, 6, 5]
3.4.8.3 filter()
The filter() method creates a new array with all elements that pass the test
implemented by the provided function. If no elements pass the test, an empty
array will be returned.
Example:
"use strict";
function isEven(value) {
return value % 2 == 0;
}
3.4.8.4 find()
The find() method returns the first element in the provided array that
satisfies the provided testing function. If no values satisfy the testing function,
undefined is returned.
Example:
"use strict";
function isEven(value) {
return value % 2 == 0;
}
3.4.8.5 findIndex()
The findIndex() method returns the index of the first element in the array
that satisfies the provided testing function. Otherwise, it returns -1 , indicating
that no element passed the test.
Example:
"use strict";
function isEven(value) {
return value % 2 == 0;
}
let foundIndex = [1, 2, 3, 4, 5].findIndex(isEven);
console.log(foundIndex); // 1
3.4.8.6 join()
The join(separator) method creates and returns a new string by
concatenating all of the elements in an array (or an array-like object), separated
by commas (default value of separator ) or a specified separator string. If the
array has only one item, then that item will be returned without using the
separator .
Example:
"use strict";
let things = ["book", "pen", 10, "eraser"];
console.log(things.join()); // book,pen,10,eraser
console.log(things.join('; ')); // book; pen; 10; eraser
3.4.8.7 map()
The map() method creates a new array populated with the results of calling a
provided function on every element in the calling array.
Example:
"use strict";
function doubleIt(value) {
return value * 2;
}
3.4.8.8 reduce()
The reduce() method executes a user-supplied "reducer" callback function
on each element of the array, in order, passing in the return value from the
calculation on the preceding element. The final result of running the reducer
across all elements of the array is a single value. This is the syntax:
// Arrow function
reduce((previousValue, currentValue, currentIndex, array) => {
// Your code here
}, initialValue)
where
● the "reducer" function that takes four arguments:
1. previousValue : the value resulting from the previous call to
callbackFn . On first call, initialValue if specified, otherwise the
value of array[0] .
2. currentValue : the value of the current element. On first call, the value
of array[0] if an initialValue was specified, otherwise the value of
array[1] .
3. currentIndex (optional): the index position of currentValue in the
array. On first call, 0 if initialValue was specified, otherwise 1 .
4. array (optional): the array to traverse.
● initialValue (optional) is a value to which previousValue is initialized
the first time the callback is called. If initialValue is specified, that also
causes currentValue to be initialized to the first value in the array. If
initialValue is not specified, previousValue is initialized to the first
value in the array, and currentValue is initialized to the second value in
the array.
Example 1:
"use strict";
const arr = [1, 2, 3, 4];
Second call 3 3 2 6
Third call 6 4 3 10
Explanation for
● the first call: Since the initialValue was not specified, previousValue
was initialized to the first item in the array( 1 ), and currentValue was
initialized to the second item in the array( 2 ). As the result,
currentIndex (index of currentValue in the array) was 1 and the
callback function returned sum of previousValue and currentValue ,
which was 3 .
● the second call: As 3 was the returned value in the previous call, 3 was
assigned to previousValue . currentIndex was increased by 1 and got
value of 2 . Therefore, currentValue was the third item in the array ( 3 ).
Finally, the callback function returned sum of previousValue and
currentValue , which was 6 .
● the third call: As 6 was the returned value in the previous call, 6 was
assigned to previousValue . currentIndex was increased by 1 and got
value of 3 . Therefore, currentValue was the fourth item in the array
( 4 ). Finally, the callback function returned sum of previousValue and
currentValue , which was 10 .
The value returned by reduce() would be that of the last callback invocation
( 10 ).
Example 2:
"use strict";
const arr = [1, 2, 3, 4];
const initialValue = 10;
const sum = arr.reduce(
(previousValue, currentValue) => previousValue + currentValue,
initialValue
);
console.log(sum); // 20
The callback function would be invoked four times, with the arguments and
return values in each call being as follows:
Callback
previousValue currentValue currentIndex return value
Iteration
First call 10 1 0 11
Second call 11 2 1 13
Third call 13 3 2 16
Fourth call 16 4 3 20
Explanation for the first call: Since the initialValue was specified( 10 ),
previousValue was initialized to its value( 10 ), and currentValue was
initialized to the first value in the array( 1 ). As the result, currentIndex (index
of currentValue in the array) was 0 and the callback function returned sum of
previousValue and currentValue , which was 11 .
The other calls worked in the same way of the previous example.
The value returned by reduce() would be that of the last callback invocation
( 20 ).
3.4.8.9 some()
The some() method tests whether at least one element in the array passes the
test implemented by the provided function. It returns true if, in the array, it
finds an element for which the provided function returns true ; otherwise, it
returns false. It doesn't modify the array.
Example:
"use strict";
function isEven(value) {
return value % 2 == 0;
}
console.log([1, 2, 3, 5].some(isEven)); // true
3.4.8.10 sort()
The sort() method sorts the elements of an array in place and returns the
sorted array. The default sort order is ascending, built upon converting the
elements into strings, then comparing their sequences of UTF-16 values.
Example 1:
"use strict";
const arr = [1, 3, 9, 2, 8];
arr.sort();
console.log(arr); // [1, 2, 3, 8, 9]
Example 2:
"use strict";
let people = [
{ name: 'Tom', age: 20 },
{ name: 'Danny', age: 42 },
{ name: 'Neo', age: 38 },
{ name: 'John', age: 15 }
];
// sort by age
people.sort(function (a, b) {
return a.age - b.age;
});
console.log(people);
// [
// { name: 'John', age: 15 },
// { name: 'Tom', age: 20 },
// { name: 'Neo', age: 38 },
// { name: 'Danny', age: 42 }
// ]
3.5 Set
The Set object lets you store unique values of any type, whether primitive
values or objects. Set objects are collections of values. You can iterate through
the elements of a set in insertion order. A value in the Set only occurs once; it is
unique in the Set's collection.
The has method of Set checks if a value is in a Set object, using an
approach that is quicker than testing most of the elements that have previously
been added to the Set object. In particular, it is faster than the
Array.prototype.includes() method when an Array object has a length equal to
a Set object's size.
console.log(set1.size); // 3
console.log(set1.has(10)); // true
console.log(set1.has(50)); // false
console.log(myMap.get('x')); // 10
myMap.set('z', 50);
console.log(myMap.get('z')); // 50
console.log(myMap.size); // 3
myMap.delete('y');
console.log(myMap.size); // 2
3.6.1 Map Iteration
A Map object iterates its elements in insertion order by using a for...of loop
which returns an array of [key, value] for each iteration.
"use strict";
let myMap = new Map();
myMap.set('x', 10);
myMap.set('y', 20);
4.1 Operators
JavaScript has many types of operators. This section describes the operators
and contains information about operator precedence.
At this point, the representation is the ones' complement of the decimal value
−9. To obtain the two's complement, 1 is added to the result, giving:
1111 01112
4.1.10.1 delete
The delete operator deletes an object's property. If the delete operator
succeeds, it removes the property from the object. The delete operator returns
true if the operation is possible; it returns false if the operation is not possible.
Syntax:
delete object.property;
delete object[propertyKey];
Example:
"use strict";
let obj = {
x: 10,
y: 20
};
delete obj.x;
console.log(obj); // { y: 20 }
4.1.10.2 typeof
The typeof operator returns a string indicating the type of the unevaluated
operand. Operand is the string, variable, keyword, or object for which the type is
to be returned.
The typeof operator is used in the following way:
typeof operand
Example:
"use strict";
typeof 62; // "number"
typeof "Hello world"; // "string"
typeof true; // "boolean"
typeof null; // "object"
typeof parseInt; // "function"
4.1.10.3 void
The void operator evaluates the given expression and then returns
undefined . The void operator is used in the following way:
void expression
The void operator is often used in these cases:
● When using an immediately-invoked function expression, void can be
used to force the function keyword to be treated as an expression instead
of a declaration.
"use strict";
void function test() {
console.log("Hello");
}();
● When a browser follows a javascript: URI, it evaluates the code in the
URI and then replaces the contents of the page with the returned value,
unless the returned value is undefined . Therefore, we use the void
operator in the following HTML code.
<a href="javascript:void(0);">
Click here to do nothing
</a>
<a href="javascript:void(document.body.style.backgroundColor='red');">
Click here for red background
</a>
4.1.11 Relational Operators
A relational operator compares its operands and returns a Boolean value
based on whether the comparison is true .
4.1.11.1 in
The in operator returns true if the specified property is in the specified
object. The syntax is:
propNameOrNumber in objectName
The following examples show some uses of the in operator.
"use strict";
// object
let obj = { x: 10, y: 20 };
"x" in obj; // true
"z" in obj; // false since "z" is not its property
// array
let things = ["book", "pen", "pencil", "eraser"];
1 in things; // true
4 in things; // false since max index is 3
"pen" in things; // returns false (you must specify the index number, not the
value at that index)
"length" in things; // returns true (length is an Array property)
4.1.11.2 instanceof
The instanceof operator returns true if the specified object is of the
specified object type. The syntax is:
objectName instanceof objectType
For example, the following code uses instanceof to determine whether the
arr variable is an Array object and the obj variable is an Object .
"use strict";
console.log(Array instanceof Object); // true
console.log(Object instanceof Array); // false
let arr = [];
console.log(arr instanceof Object); // true
console.log(arr instanceof Array); // true
19 Grouping (…)
Postfix Increment … ++
16
Postfix Decrement … --
Prefix Increment ++ …
15 right-to-left
Prefix Decrement -- …
typeof typeof …
void void …
delete delete …
await await …
14 Exponentiation (**) right-to-left … ** …
in … in …
instanceof … instanceof …
Equality (==) … == …
Inequality (!=) … != …
9 left-to-right
Strict Equality (===) … === …
…=…
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
Assignment right-to-left
… >>= …
2
… >>>= …
… &= …
… ^= …
… |= …
… &&= …
… ||= …
… ??= …
yield yield …
right-to-left
yield* yield* …
4.3.1 try...catch
The try...catch statement marks a block of statements to try and specifies a
response should an exception be thrown.
Syntax:
try {
// try statements
}
catch (exceptionVariable) {
// catch statements
}
finally {
// finally statements
}
where
● exceptionVariable is an optional identifier to hold an exception object
for the associated catch -block.
The try statement consists of a try -block, which contains one or more
statements. {} must always be used, even for single statements. A catch -block,
a finally -block, or both must be present. This gives us three forms for the try
statement:
try...catch
try...finally
try...catch...finally
A catch -block contains statements that specify what to do if an exception is
thrown in the try -block. If any statement within the try -block (or in a function
called from within the try -block) throws an exception, control is immediately
shifted to the catch -block. If no exception is thrown in the try -block, the
catch -block is skipped.
The finally -block will always execute after the try -block and catch -
block(s) have finished executing. It always executes, regardless of whether an
exception was thrown or caught.
Example:
"use strict";
try {
const MY_CONST = 10;
MY_CONST = 20;
console.log('This is an unreachable line of code');
}
catch (error) {
console.log(error);
// TypeError: Assignment to constant variable.
}
finally {
// always execute after try-block and catch-block
console.log('finally statement');
}
4.3.2 throw
The throw statement throws a user-defined exception. Execution of the
current function will stop (the statements after throw won't be executed), and
control will be passed to the first catch -block in the call stack. If no catch -
block exists among caller functions, the program will terminate.
Some examples of throw expressions:
throw 'Error here';
throw -1;
throw false;
throw new Error('Error here');
You can specify an object when you throw an exception. You can then
reference the object's properties in the catch -block. The following example
creates an object of type UserException and uses it in a throw statement.
"use strict";
function UserException(message) {
this.message = message;
this.name = 'UserException';
}
function processUserInput(data) {
if (data instanceof Object) {
// process user's input
}
else {
throw new UserException("Invalid User's Input");
}
}
function getDayString(day) {
switch (day) {
case 0:
console.log("Sunday");
break;
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
case 4:
console.log("Thursday");
break;
case 5:
console.log("Friday");
break;
case 6:
console.log("Saturday");
break;
default:
console.log("Invalid day");
}
}
getDayString(5); // Friday
getDayString(7); // Invalid day
Example 2:
"use strict";
function getDayType(day) {
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
console.log("Working day");
break;
case 0:
case 6:
console.log("Weekend");
break;
default:
console.log("Invalid day");
}
}
getDayType(2); // Working day
getDayType(3); // Working day
getDayType(0); // Weekend
If you forget a break then the script will run from the case where the
criterion is met and will run the cases after that regardless if a criterion was met.
Example 3:
"use strict";
function test(myVar) {
switch (myVar) {
case 1:
console.log(1);
case 2:
console.log(2);
break;
case 3:
console.log(3);
break;
default:
console.log('default');
}
}
test(1);
// 1
// 2
4.3.5 Loops and Iteration
Loops offer a quick and easy way to do something repeatedly. This section
introduces the different iteration statements available to JavaScript.
The various loop mechanisms offer different ways to determine the start and
end points of the loop. There are various situations that are more easily served
by one type of loop over the others.
The statements for loops provided in JavaScript are:
4.3.5.1 for
A for loop repeats until a specified condition evaluates to false . A for
statement looks as follows:
for ([initialExp]; [conditionExp]; [incrementExp]) {
statements
}
When a for loop executes, the following occurs:
1. The initializing expression initialExp , if any, is executed. This
expression usually initializes one or more loop counters, but the syntax
allows an expression of any degree of complexity. This expression can
also declare variables.
2. The conditionExp expression is evaluated. If the value
of conditionExp is true , the loop statements execute. If the value
of condition is false , the for loop terminates. (If
the condition expression is omitted entirely, the condition is assumed
to be true .)
3. The statements are executed. To execute a single statement, we can
omit the block statement ( {} ).
4. If present, the update expression incrementExp is executed.
5. Control returns to Step 2.
Example:
"use strict";
let arr = [10, 20, 30];
for (let index = 0; index < arr.length; index++) {
console.log(arr[index]);
}
// 10
// 20
// 30
4.3.5.2 for...in
The for...in statement iterates a specified variable over all the enumerable
properties of an object. For each distinct property, JavaScript executes the
specified statements. A for...in statement looks as follows:
for (variable in object) {
statements
}
The following example prints all properties of an object and their values.
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman",
email: "neodtruman@gmail.com"
};
for (let propName in obj) {
console.log(propName + " = " + obj[propName]);
}
// "firstName = Neo"
// "lastName = D. Truman"
// "email = neodtruman@gmail.com"
4.3.5.3 for...of
The for...of statement creates a loop iterating over iterable objects (including
Array, Map, Set, arguments object and so on), invoking a custom iteration hook
with statements to be executed for the value of each distinct property.
for (variable of object) {
statements
}
Let’s try this example.
"use strict";
let things = ["book", "pen", "eraser"];
for (let item of things) {
console.log(item);
}
// book
// pen
// eraser
4.3.5.4 while
A while statement executes its statements as long as a specified condition
evaluates to true . A while statement looks as follows:
while (condition) {
statements
}
The condition test occurs before statements in the loop are executed. If the
condition returns true , statements are executed and the condition is tested
again. If the condition returns false , execution stops, and control is passed to
the statement following while .
To execute a single statement, we can omit the block statement ( {} ).
Example:
"use strict";
let i = 0;
while (i < 3) {
i++;
console.log(i);
}
// 1
// 2
// 3
4.3.5.5 do...while
The do...while statement repeats until a specified condition evaluates to
false . A do...while statement looks as follows:
do {
statements
} while (condition);
statements are always executed once before the condition is checked. To
execute a single statement, we can omit the block statement ( {} ).
If condition is true , the statement executes again. At the end of every
execution, the condition is checked. When the condition is false , execution
stops.
"use strict";
let i = 0;
do {
i++;
console.log(i);
} while (i < 3);
// 1
// 2
// 3
4.3.5.6 label
A label provides a statement with an identifier that lets you refer to it
elsewhere in your program. For example, you can use a label to identify a loop,
and then use the break or continue statements to indicate whether a program
should interrupt the loop or continue its execution.
The syntax of the labeled statement looks like the following:
label:
statement
The value of label may be any JavaScript identifier that is not a reserved
word. The statement that you identify with a label may be any statement.
In this example, the myLoop label identifies a while loop.
"use strict";
myLoop:
while (theFlag === true) {
doSomething();
}
4.3.5.7 break
Use the break statement to terminate a loop, switch , or in conjunction with
a labeled statement.
● When you use break without a label, it terminates the innermost
enclosing while, do-while, for , or switch immediately and transfers
control to the following statement.
● When you use break with a label, it terminates the specified labelled
statement.
The syntax of the break statement looks like this:
● The first form of the syntax terminates the innermost enclosing loop or
switch.
break;
● The second form of the syntax terminates the specified enclosing labeled
statement.
break [label];
The following example iterates through the elements in an array until it finds
the index of an element whose value is theValue :
"use strict";
let theValue = 3;
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
if (arr[i] === theValue) {
break;
}
}
// 1
// 2
// 3
And this is an example of breaking a labelled statement.
"use strict";
for (let i = 1; i < 5; i++) {
the2ndLoop:
for (let j = 1; j < 5; j++) {
for (let k = 1; k < 5; k++) {
console.log(`[i, j, k] = [${i}, ${j}, ${k}]`);
if (k === j * 2 && j === i * 2) {
console.log('Break the 2nd loop');
break the2ndLoop;
}
}
}
}
// [i, j, k] = [1, 1, 1]
// [i, j, k] = [1, 1, 2]
// [i, j, k] = [1, 1, 3]
// [i, j, k] = [1, 1, 4]
// [i, j, k] = [1, 2, 1]
// [i, j, k] = [1, 2, 2]
// [i, j, k] = [1, 2, 3]
// [i, j, k] = [1, 2, 4]
// Break the 2nd loop
// [i, j, k] = [2, 1, 1]
// [i, j, k] = [2, 1, 2]
// [i, j, k] = [2, 1, 3]
// ...
// [i, j, k] = [4, 4, 4]
4.3.5.8 continue
The continue statement can be used to restart a while, do-while, for , or
label statement.
● When you use continue without a label, it terminates the current
iteration of the innermost enclosing while, do-while , or for statement
and continues execution of the loop with the next iteration. In contrast to
the break statement, continue does not terminate the execution of the
loop entirely. In a while loop, it jumps back to the condition . In a for
loop , it jumps to the increment-expression .
● When you use continue with a label, it applies to the looping statement
identified with that label.
The syntax of the continue statement looks like the following:
continue [label];
Example:
"use strict";
let i = 0;
while (i < 5) {
i++;
if (i === 3) {
continue;
}
console.log(i);
}
// 1
// 2
// 4
// 5
If continue is encountered, the program terminates the current iteration of
checkj and begins the next iteration. Each time continue is encountered, checkj
reiterates until its condition returns false .
"use strict";
the1stLoop:
for (let i = 1; i < 5; i++) {
for (let j = 1; j < 5; j++) {
for (let k = 1; k < 5; k++) {
console.log(`[i, j, k] = [${i}, ${j}, ${k}]`);
if (k === j * 2 && j === i * 2) {
console.log('Continue at the 1st loop');
continue the1stLoop;
}
}
}
}
// [i, j, k] = [1, 1, 1]
// [i, j, k] = [1, 1, 2]
// [i, j, k] = [1, 1, 3]
// [i, j, k] = [1, 1, 4]
// [i, j, k] = [1, 2, 1]
// [i, j, k] = [1, 2, 2]
// [i, j, k] = [1, 2, 3]
// [i, j, k] = [1, 2, 4]
// Continue at the 1st loop
// [i, j, k] = [2, 1, 1]
// [i, j, k] = [2, 1, 2]
// [i, j, k] = [2, 1, 3]
// ...
// [i, j, k] = [4, 4, 4]
4.4 Destructuring Assignment
The destructuring assignment syntax is a JavaScript expression that makes it
possible to unpack values from arrays, or properties from objects, into distinct
variables.
let result = 0;
for (let i = 0; i < numbers.length; i++) {
result += numbers[i];
}
return result;
}
console.log(sum(10, 20, 30)); // 60
console.log(sum(10, 20, 30, 40)); // 100
And this is an example of using rest parameters in combination with ordinary
parameters.
"use strict";
function multiply(multiplier, ...numbers) {
let result = [];
for (let i = 0; i < numbers.length; i++) {
result.push(numbers[i] * multiplier);
}
return result;
}
let arr = multiply(2, 10, 20, 30);
console.log(arr); // [20, 40, 60]
5.5 The arguments Object
The arguments object of a function is a special object that contains all
arguments which were inputted by users.
Example:
"use strict";
function sum() {
let total = 0;
for (let n of arguments) {
total += n;
}
return total;
}
console.log(sum(1, 2, 3, 4, 5)); // 15
5.6 Recursive Function
A recursive function calls itself in its function body.
For example, consider the following function which will calculate a summary
of integers from start number to end number. To focus on the concept, we
don’t put the validation code of the parameters.
"use strict";
function sum(start, end) {
let result = 0;
for (let i = start; i <= end; i++) {
result += i;
}
return result;
}
console.log(sum(2, 6)); // 2 + 3 + 4 + 5 + 6 = 20
We can write the above example in another way as a recursive function.
"use strict";
function sum(start, end) {
return start === end ? end : start + sum(start + 1, end);
}
console.log(sum(2, 6));
// = 2 + sum(3, 6)
// = 2 + 3 + sum(4, 6)
// = 2 + 3 + 4 + sum(5, 6)
// = 2 + 3 + 4 + 5 + sum(6, 6)
// = 2 + 3 + 4 + 5 + 6
function add() {
return num1 + num2 + x + y;
}
console.log(add()); // 33
}
test();
Example 1:
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman"
};
function logInfo() {
console.log(this.firstName + " " + this.lastName);
}
let logInformation = logInfo.bind(obj);
logInformation(); // Neo D. Truman
Example 2: input arguments into bind()
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman"
};
function logInfo(email) {
console.log(this.firstName + " " + this.lastName);
console.log(email);
}
let logInformation = logInfo.bind(obj, "neodtruman@gmail.com");
logInformation();
// Neo D. Truman
// neodtruman@gmail.com
Example 3: does not input arguments into bind()
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman"
};
function logInfo(email) {
console.log(this.firstName + " " + this.lastName);
console.log(email);
}
let logInformation = logInfo.bind(obj);
logInformation("neodtruman@gmail.com");
// Neo D. Truman
// neodtruman@gmail.com
5.13.2 call
The Function.prototype.call() method works in the same way as bind()
however call() will invoke the function (as its name, “call”) but bind() does
not.
The syntax is:
call(thisArg, arg1, ... , argN)
where
● thisArg is the object that the this keyword will point to
● arg1, arg2, ...argN (optional) are arguments of the function.
Example 1:
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman"
};
function logInfo() {
console.log(this.firstName + " " + this.lastName);
}
logInfo.call(obj); // Neo D. Truman
Example 2:
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman"
};
function logInfo(email) {
console.log(this.firstName + " " + this.lastName);
console.log(email);
}
logInfo.call(obj, "neodtruman@gmail.com");
// Neo D. Truman
// neodtruman@gmail.com
call() provides a new value of this to the function/method. With call() , you
can write a method once and then inherit it in another object, without having to
rewrite the method for the new object.
"use strict";
let obj1 = {
firstName: "Neo",
lastName: "D. Truman",
getFullname: function () {
return this.firstName + " " + this.lastName;
}
};
let obj2 = {
firstName: "John",
lastName: "Conner",
}
let fullname = obj1.getFullname.call(obj2);
console.log(fullname); // John Conner
We can also use call() to chain constructors for an object like the below
example.
"use strict";
function Thing(name, price) {
this.name = name;
this.price = price;
}
Example:
"use strict";
let obj = {
firstName: "Neo",
lastName: "D. Truman"
};
function logInfo(email) {
console.log(this.firstName + " " + this.lastName);
console.log(email);
}
// We can get email from user and push it into the array of arguments
let args = ["neodtruman@gmail.com"];
logInfo.apply(obj, args);
// Neo D. Truman
// neodtruman@gmail.com
5.14 Closure
5.14.1 Closure Introduction
A closure gives you access to an outer function's scope from an inner
function. In JavaScript, closure is created every time a function is created inside
another function and the function does use its parent’s variables.
"use strict";
function sayHi(firstName) {
let lastName = 'D. Truman';
return function doLog(message) {
debugger;
console.log(
`Hello ${firstName} ${lastName}. ${message}`
);
}
}
function sayHi(firstName) {
let lastName = 'D. Truman';
return function doLog(message) {
debugger;
console.log(message);
}
}
return {
getUpperCaseName: function () {
debugger;
return allCap(name);
},
getName: function () {
return name;
},
setName: function (newName) {
name = newName;
}
}
}
let u = makeUserObject();
console.log(u);
console.log(u.name); // undefined
console.log(u.allCap); // undefined
console.log(u.getUpperCaseName()); // 'NEO'
u.setName('John');
console.log(u.getName()); // 'John'
When we run the above code, debugger of the browser will stop at the
debugger breakpoint (line 10) as the below picture.
function processName(callback) {
let name = 'Neo';
callback(name);
}
processName(doLog);
processName(doAlert);
5.16 Generator Function
The function* is exactly a generator that returns different values based on
the yield expressions inside the function body or the yield* , to another
generator function.
The next() method of generators returns an object with value and done
properties.
Example 1:
"use strict";
function* generator(x) {
yield x;
yield x * 2;
yield x * 5;
}
function* generator(x) {
yield x;
yield x * 2;
yield* anotherGenerator(x);
yield x * 5;
}
// function expression
let testFunc2 = function () {
console.log(this); // Window object
}
testFunc2();
// nested functions
function test3() {
// function declaration
function testFunc3() {
console.log(this); // Window object
}
testFunc3();
}
test3();
function test4() {
// arrow function expression
let testFunc4 = () => {
console.log(this); // Window objects
}
testFunc4();
}
test4();
this in arrow function expressions, which is not in another function, is
always (in both strict mode and non-strict mode) the Window object when
working on a Web Browser.
"use strict";
// arrow function expression
let testFunc5 = () => {
console.log(this); // Window object
}
testFunc5();
In strict mode, this in functions (except the arrow functions) is undefined in
as the below example.
"use strict";
// function declaration
function testFunc1() {
console.log(this); // undefined
}
testFunc1();
// function expression
let testFunc2 = function () {
console.log(this); // undefined
}
testFunc2();
// nested functions
function test3() {
// function declaration
function testFunc3() {
console.log(this); // undefined
}
testFunc3();
}
test3();
function test4() {
// arrow function expression
let testFunc4 = () => {
console.log(this); // undefined
}
testFunc4();
}
test4();
6.2 this in Object’s Methods
Since object’s methods are also functions, the this keyword in the methods
behaves the same as in functions (described in the previous section) except
methods that are defined using function expressions.
this in methods that are defined using function expressions is always the
object as in the below examples.
Example 1:
"use strict";
let user = {
name: 'Neo',
logInfo: function () { // function expression
console.log(this);
},
showInfo: () => {
console.log(this);
}
}
user.logInfo(); // {name: 'Neo', logInfo: f, showInfo: f}
user.showInfo(); // Window object
Example 2:
"use strict";
function testUser() {
let user = {
name: 'Neo',
logInfo: function () { // function expression
console.log(this);
},
showInfo: () => {
console.log(this);
}
}
user.logInfo(); // {name: 'Neo', logInfo: f, showInfo: f}
user.showInfo(); // undefined
}
testUser();
Example 3: this in nested function will be undefined
"use strict";
let user = {
firstName: 'Neo',
lastName: 'D. Truman',
showFullname: function () {
console.log(this.firstName + ' ' + this.lastName);
function sayHi() {
console.log(this); // undefined
console.log('Hi ' + this.firstName + ' ' + this.lastName); // TypeError
}
sayHi();
}
}
user.showFullname();
Example 4: a solution for example 3 is saving the pointer to object at outer
function and use it in the inner function (a closure)
"use strict";
let user = {
firstName: 'Neo',
lastName: 'D. Truman',
showFullname: function () {
console.log(this.firstName + ' ' + this.lastName);
let self = this;
function sayHi() {
console.log(self);
// self is {firstName: 'Neo', lastName: 'D. Truman', showFullname: f}
console.log('Hi ' + self.firstName + ' ' + self.lastName);
// Hi Neo D. Truman
}
sayHi();
}
}
user.showFullname();
We should not use arrow functions in these cases:
● Case #1: Define methods in object or class. Examples are as above.
● Case #2: Define callback events of DOM’s elements.
● Case #3: Define methods in object’s prototype.
User.prototype.logInfo = () => {
console.log(this);
}
User.prototype.showInfo = function () {
console.log(this);
}
let user = {
name: 'Neo',
sayHi: welcome
}
user.sayHi();
6.2.2 Implicit Lost Binding
Continue the example of implicit binding, we assign the object’s method to a
variable and invoke it as a function expression. As a result, this in function
expression will be undefined .
"use strict";
function welcome() {
console.log(this); // undefined
console.log('Hi ' + this.name); // TypeError
}
let user = {
name: 'Neo',
sayHi: welcome
}
let greetingFunc = user.sayHi;
greetingFunc();
6.3 globalThis
The globalThis property is used to ensure working on the global object of the
current environment. In the case of web browsers, globalThis is always the
Window object.
An example that is run on a web page:
"use strict";
function test() {
console.log(this); // undefined
console.log(globalThis); // Window object
}
test();
CHAPTER 7
Some Advanced Concepts
It's time to introduce some advanced concepts since we already know many
concepts about the JavaScript language.
In the creation phase, a Syntax Parser reads our code line-by-line and create
space/memory for variable and function declarations (not the expressions).
Right after the creation phase, JavaScript engine will do the execution phase.
Since JavaScript is a single-threaded language, JavaScript engine will execute
our code line-by-line from the beginning to the end of the code.
Let’s try this example.
"use strict";
debugger; // #1
function aFooFunc() {
let myVar = 10;
aBarFunc();
console.log(myVar); // 10
}
function aBarFunc() {
myFunc();
console.log(myVar); // 100
}
let myFunc = function() {
console.log('myFunc');
debugger; // #2
}
Example:
"use strict";
function sayHi(firstName) {
let lastName = 'D. Truman';
console.log(`Hello ${firstName} ${lastName}`);
debugger;
}
A common mistake is not realizing that in the case where the outer function is
itself a nested function, access to the outer function's scope includes the
enclosing scope of the outer function — effectively creating a chain of function
scopes. To demonstrate, consider the following example code.
"use strict";
function sayHi(firstName) {
let lastName = 'D. Truman';
return function doGreeting(greeting) {
return function doLog(message) {
let name = `${firstName} ${lastName}`;
console.log(
`${greeting} ${name}. ${message}`
);
debugger;
}
}
}
In the above picture, the doLog() function can access to these variables in
the below scope chain:
● Local variables
function test() {
console.log('Hello');
}
Since the function definition was created in the Creation Phase, the test()
function could be invoked in the Execution Phase.
Variable hoisting does not work with the let and const
keywords. It will raise an error if we write code like the below
example.
"use strict";
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
CHAPTER 8
Promise
promise1
.then((value) => {
console.log(value);
})
.catch(error => {
console.log(error);
});
8.1.2 Promise Chain
One of the great things about using promises is chaining. A common need is
to execute two or more asynchronous operations, where each subsequent
operation starts when the previous operation succeeds, with the result from the
previous step. We accomplish this by creating a promise chain.
Example:
"use strict";
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
console.log('Do this');
})
.then(() => {
console.log('Do that');
})
.finally(() => {
console.log('Completed');
});
This will output the following text:
Initial
Do this
Do that
Completed
8.1.3 Chaining After a Catch
It's possible to chain after a failure (i.e., a catch) which is useful to
accomplish new actions even after an action failed in the chain. Try the
following example:
"use strict";
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do that');
})
.catch(() => {
console.error('Caught the error');
})
.then(() => {
console.log('Do this, no matter what happened before');
})
.finally(() => {
console.log('Completed');
});
This will output the following text:
Initial
Caught the error
Do this, no matter what happened before
Completed
8.1.4 Error Propagation
If there's an exception, the browser will look down the chain for the catch()
handlers or onRejected .
"use strict";
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
console.log('Do this');
})
.then(() => {
console.log('Do that');
})
.then(() => {
throw new Error('Something failed');
})
.then(() => {
console.log('Is this line printed?'); // No
})
.catch(() => {
console.error('Caught the error');
});
This will output the following text:
Initial
Do this
Do that
Caught the error
8.2 Composition
8.2.1 Parallel Composition
8.2.1.1 Promise.all()
The Promise.all() method takes an iterable of promises as an input, and
returns a single Promise that resolves to an array of the results of the input
promises.
This method can be useful for aggregating the results of multiple promises. It
is typically used when there are multiple related asynchronous tasks that the
overall code relies on to work successfully — all of whom we want to fulfill
before the code execution continues.
Example 1:
"use strict";
8.2.1.2 Promise.allSettled()
In comparison to Promise.all() , the promise returned by
Promise.allSettled() will wait for all input promises to complete, regardless of
whether or not one rejects as the Example 3. Consequently, it will always return
the final result of every promise and function from the input iterable.
Example 3:
"use strict";
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('A rejected case'));
}, 2000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('faster'), 1000);
});
let p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('slow'), 4000);
});
8.2.1.3 Promise.race()
The Promise.race() method returns a promise that fulfills or rejects as soon
as one of the promises in an iterable fulfills or rejects, with the value or reason
from that promise.
Example 4:
"use strict";
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('A rejected case'));
}, 2000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('faster'), 1000);
});
let p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('slow'), 4000);
});
8.2.1.4 Promise.any()
Promise.any() takes an iterable of Promise objects. It returns a single
promise that resolves as soon as any of the promises in the iterable fulfills, with
the value of the fulfilled promise. If no promises in the iterable fulfill (if all of
the given promises are rejected), then the returned promise is rejected with an
AggregateError , a new subclass of Error that groups together individual errors.
Example 6:
"use strict";
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('A rejected case'));
}, 2000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('faster'), 1000);
});
let p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('slow'), 4000);
});
Promise.resolve()
.then(() => console.log(2)) // line 7
.then(() => console.log(3)); // line 8
console.log(5); // line 12
console.log(6); // line 13
// 5
// 6
// 2
// 3
// 1
// 4
Explanation:
Execute Microtask queue Task queue
Line 4 console.log(1);
Line 7 console.log(2);
Line 8 console.log(2);
console.log(3);
Line 10 console.log(1);
console.log(4);
Line 12 Print “5” to the console panel.
Line 13 Print “6” to the console panel.
After line Execute all microtasks (before execute the next task if any).
13
Print “2” to the console panel.
Print “3” to the console panel.
Execute all remain tasks.
Print “1” to the console panel.
Print “4” to the console panel.
8.4 Async Function
An async function is a function declared with the async keyword, and the
await keyword is permitted within it. The async and await keywords enable
asynchronous, promise-based behavior to be written in a cleaner style, avoiding
the need to explicitly configure promise chains.
Async functions can contain zero or more await expressions. Await
expressions make promise-returning functions behave as though they're
synchronous by suspending execution until the returned promise is fulfilled or
rejected. The resolved value of the promise is treated as the return value of the
await expression.
Example:
"use strict";
function downloadImage() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Finished downloading');
}, 2000);
});
}
asyncCall();
About the Author
Neo D. Truman has been using computers since 1998 when he was a child. He’s
got a Master of Science in Information Technology degree in 2011. He has 15+
years of experience in software development, especially full-stack web
development.
Other Books by The Author
https://www.amazon.com/dp/B0B1JCCP3S
https://www.amazon.com/dp/B09X7FB99L
Please leave a Review/Thought on Amazon
Thank you for purchasing and reading my book. I am extremely grateful and
hope you found value in reading it.
Please consider sharing it with friends or family and leaving a review on the
Amazon website. Your feedback and support are always appreciated, and inspire
me to continue doing what I love. Please go to Amazon and leave a review if
you’d like my book.
My email is neodtruman@gmail.com. If you have any questions, please send
me an email. I am always happy to hear from people who’ve read my books. I’ll
try my best to answer every email I receive. The subject should be “[JavaScript
for Dummies] <Your subject here>” so that I could filter and answer your
questions quickly.
You can also follow me on the Amazon Author page,
https://www.amazon.com/Neo-D-Truman/e/B09P6LHL2M