0% found this document useful (0 votes)
7 views45 pages

002 JavaScript -

The document provides an overview of essential JavaScript skills for Salesforce developers, focusing on core concepts, the JavaScript runtime, and its application in Lightning Web Components. It covers variable declaration, type coercion, the Document Object Model (DOM), and encapsulation with Shadow DOM, as well as object creation and manipulation. The content emphasizes the importance of understanding JavaScript to effectively develop interactive web applications within the Salesforce ecosystem.

Uploaded by

superadforce
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views45 pages

002 JavaScript -

The document provides an overview of essential JavaScript skills for Salesforce developers, focusing on core concepts, the JavaScript runtime, and its application in Lightning Web Components. It covers variable declaration, type coercion, the Document Object Model (DOM), and encapsulation with Shadow DOM, as well as object creation and manipulation. The content emphasizes the importance of understanding JavaScript to effectively develop interactive web applications within the Salesforce ecosystem.

Uploaded by

superadforce
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 45

https://trailhead.salesforce.

com/content/learn/trails/learn-to-work-with-javascript

Part 1 - JavaScript Skills for Salesforce Developers - Module


Learn key JavaScript skills and how they apply to writing Lightning web components.
* lwc = Lightning Web Components
To open JavaScript Editor on Chrome -> (ctrl+shift+j)

Lesson 1: Learn JavaScript Core Concepts:

JavaScript was primarily a way to make web-pages somewhat interactive, and to execute
rudimentary logic without a server trip. Server-side frameworks were extremely popular,
including the Salesforce framework Visualforce. As testimony to this popularity, there are
millions of Visualforce pages live in Salesforce today.

NOW (as of February 2024) JavaScript is well standardized around the ECMAScript standard,
and top browser manufacturers are generally good about adopting new features. Web
applications today have rich user interfaces running modern JavaScript in the browser.
Instead of server-side frameworks, modern web applications tend to be client-side rendered.
In Salesforce, this is done with the Lightning Component Framework. But writing JavaScript is
still new for many developers. If you’ve worked mostly with Visualforce pages and Apex
controllers, you might need a leg up to really get how JavaScript works so you can better
understand your components.

The JavaScript runtime is an engine that interprets JavaScript code. It can be part of a
browser, or other runtime environment like a server. The defining feature of the JavaScript
engine is a single-threaded runtime represented by the stack below. Work being done in the
stack owns the thread and must complete its synchronous logic before it hands back control
of the thread.
The runtime is a busy place. New work can come in at any time from a number of
origins, including the user (UI events) and web APIs (such as geolocation or device
motion). Since there’s only one thread, there is a queue where work awaits its turn to
use the thread.

When the stack is empty, the event loop takes work that is waiting to be done from
the queue and moves it into the stack.

*JavaScript is built according to the ECMAScript standard and it’s constantly changing and
being updated.

Things to Know about JavaScript:


1) JavaScript is CASE SENSITIVE! (Where Apex and SOQL is not Case Sensitive)
2) To create Variables use let and const (var is rarely used)
3) remember that const only prevents reassigning your variable to a different object.
The object itself (its properties, functions, and so on) can still be changed

Keyword Scope Mutable Assignment


var function yes
let block yes
const block no

All variables are pointers. Assignment is the act of pointing that variable to something in
memory. Mutability is whether or not a variable can be reassigned once it has initially been
assigned something. Using var or let creates mutable pointers, whereas const is
immutable.

4) Implicit Type Coercion


When most JavaScript operators encounter an invalid type, they attempt to convert
the value to a valid type. This process of implicitly converting a type is called implicit
type coercion. Consider the
following:

In the first example the * operator can only be used for math operations, using the
string "3" to a number. The outcome is 27. In the second, the + operator sees the
string "3" making it a mathematical operator . This use 9 to the string "9" with an
outcome of the string "93" .
5) For Boolean comparison the best practice is to use === and !==

6) Truthy and Falsy:

When an expression expects a Boolean value, the following values are always treated
as false.
• false (of course)

• 0 (the number zero)

• "" or '' (an empty string)


• null
• undefined

• NaN (the result of failed mathematical operations)

7) this Is Tricky: this has well-defined rules, but what this points to can change
even within the same function. For instance, in an Apex class you might
see:

In this example Apex class, this only ever refers to the current instance of MyApexClass . In
JavaScript, what this points to is not determined by where a function is defined, but rather
where that function is called. More on this later.
8) Functions Are Values: In JavaScript, everything is an object. This goes for functions
too. And like other objects, functions can be assigned to variables, passed into
parameters of other functions, and used the same way you can any other object.

Lesson 2: Understand JavaScript in the Browser


The JavaScript Runtime Is Not the Browser, Nor Is the Browser JavaScript. JavaScript runtime
engine runs in many different places, but it’s most often hosted in a browser. A browser’s
primary job is to act as a client for a web server. It requests resources over the Internet, using
one of several protocols (usually HTTP/HTTPS). Once a server passes it some of those
resources, the browser needs to do something with them. At a minimum HTML and CSS are
rendered into a page. When a resource contains some JavaScript, the browser reaches over
to the JavaScript runtime engine to parse, evaluate, and execute that code.

Likewise, while a script is executing it can also reach back to the browser to do things like
modify the web page, interact with the local environment, or interact with other web
resources. To make these interactions work, the browser surfaces APIs. In fact, a large part of
what people think of as client-side JavaScript is actually these APIs

Web APIs:
While over half of browser internet traffic comes from Google Chrome, roughly another 30
percent comes from five other browsers. This underscores the importance of the web
standards for these APIs, so that JavaScript can be written once and run anywhere.

Adding Web APIs to the Picture


Previously we created a picture of the JavaScript runtime.
• Requests execute on the stack using a single thread.
• A request holds the thread until it is done executing all synchronous logic for
that request.
• New requests are queued until the thread is ready.
• The event loop moves the next queued request into the stack when it
becomes available.
We’re now adding web APIs to our picture of JavaScript. These extend the core
JavaScript language. They surface interfaces that perform much of the work that is
critical to the user experience of the modern web. For example, browser APIs can:
• Interact with the structure of the current page rendered in the browser
(Document Object Model or DOM API)
• Perform asynchronous requests to the server without leaving the current page
(Fetch API)
• Interact with audio, video, and graphics
• Interact with device features surfaced to the browser (geolocation, device
orientation, client-side data storage)
Most of the time it is these APIs that add new requests to the queue.

We’re sidestepping an important piece of the JavaScript ecosystem: third-party


APIs and JavaScript libraries that abstract or extend browser capabilities. These
play an important role in how JavaScript is used in the wild.

For our purposes in the context of Salesforce, we cover our JavaScript


framework: the Lightning Component Framework. Specifically, when talking
about JavaScript on the Lightning Platform, this module addresses the
Lightning Web Component development model.

For example: You have a list of notes on a web page with a form. You fill out some
fields on the form, click a button to save that data, and a new item is added to the
list. For fun, let’s say also that you will cache this new record locally to speed up
future requests involving that record.
This simple use case would interact with the following browser APIs
• Fetch API (to save the record)
• DOM API (to add a new item to an HTML list)
• Client-Data Storage (to cache the data locally)

The DOM API - what the user sees within JavaScript:


The Document Object Model: The DOM: Your Page on JavaScript:

When a page is requested and then received by a browser, the browser analyze the HTML
and creates a description, or a model, of that page. This model is used to draw the page in
the browser’s viewport. It’s also surfaced to JavaScript through the DOM.

Think of the DOM as a tree. It starts at the root of the browser’s display functionality: the
window. From there, the page is encapsulated in window.document , with the page’s body
in window.document.body . Then the tree fans out to every bit of content represented on the
page. Most web pages have a very complex tree with many nodes finally ending in leaf
nodes as the most granular pieces of the
hierarchy.

As an API, the DOM is vast, and lets you touch every part of this tree. It also has a
number of methods to optimize interaction with the DOM. Take a look at this
simple example on jsbin.com. It includes:

• An input field
• An Add Item button
• An unordered list

Each time you click the button, the code reaches into the input field, reads its value,
converts it to a text node, creates a new li element, inserts the text node into
the li node, and finally sticks the new li -and-text node into the ul .

As you can see, just this simple example requires the developer to perform a bunch of
manual steps. And it doesn’t even store any data on a server, or interact with a server in any
other way. For this reason, JavaScript libraries (reactjs, jQuery) and frameworks (Angular,
vuejs) have become the standard for interactive pages. Such frameworks abstract away and
simplify DOM interactions, and often automatically apply polyfills (A polyfill - allows web
developers to use an API regardless of whether or not it is supported by a browser, and usually with
minimal overhead. Typically they first check if a browser supports an API, and use it if available,
otherwise using their own implementation). for missing features. The Lightning Component
Framework is no different.

Encapsulation (enclosing, working with) with Shadow DOM:

The DOM API is rich and flexible. Using relatively simple JavaScript it is easy to make
changes to the looks, behaviors, and actions invoked by the UI.

But there is a pitfall. The DOM model makes it difficult to encapsulate pieces of the
UI and protect them from accidental (or purposeful and malicious) changes.

For this reason, the Shadow DOM standard was developed. Shadow DOM creates a
boundary around a particular part of UI functionality. The boundary prevents a
parent from changing the elements or CSS of a child. It also forces any events
propagated across the boundary to rescope their targets, preventing the parent from
reaching across the shadow DOM boundary.

Lightning Web Components and the DOM:


1) Automatic DOM Updates:

• The fundamental value of Lightning components is in building a custom UI


driven by Salesforce data. This ties in to DOM manipulation because the DOM
itself is driven by Salesforce data.
• This component demonstrates this principle in its simplest form.

Here is the code of this component:

First some context: Every Lightning web component requires a JavaScript


module. If the component contains any elements to be presented to the user, an
HTML template is required, too. Most components contain a JavaScript and an HTML
file in what’s called a bundle.

If you want the UI to change when the user interacts with it:

Lightning Web Components make it effortless to render data into UI. For example,
the code above uses the JavaScript property text to store a hard coded string. In
the <lightning-formatted-text> tag, the value attribute is bound to the
JavaScript text property, rendering the data in the UI.

But what if you want the UI to change when the user interacts with it? We can
extend this example to do just that. https://youtu.be/5KRjiCArONM

In a Lightning web component, JavaScript class properties are reactive. This means
when a property’s value is assigned (or reassigned), and the property is used in a
template, the component's DOM re-renders and displays the new value.

In the template we added a <lightning-input> . Although binding the text properties


is key to displaying the data, notice the onchange attribute. The handleChange function
that’s been added to the JavaScript class now is triggered by change events. Each
modification to the value by the user updates the value of text . When text is
updated, so is the DOM.

Explicit DOM Manipulation

Manual DOM manipulation shouldn't be your first strategy when building a Lightning
web component, but more sophisticated components may require you to do so. This
is a more advanced topic, but it’s worth scratching the surface of how this works
before signing off on the DOM.

Conditional Rendering
When writing Lightning web components, you can explicitly define sections of the UI
that are rendered only when certain conditions are met. You can do this by using
the lwc:if , lwc:elseif , and lwc:else directives with nested template tags.

In this code sample, the text Peek-a-boo! appears when the show property has a
value of true . When show is set to false , the text I’m hiding! appears. Clicking the
button toggles the value of the show property.

• In some circumstances, it’s OK to manually manipulate the DOM element


display using the display CSS style. Although this method works as usual in
Lightning Web Components, it’s beyond the scope of this particular module.

Lesson 3: Work with Objects, Classes, and Prototypical


Inheritance:
A few notes on JavaScript objects in before we get started.

• Objects don’t have classes the way an Apex, Java, or C# developer might think
of them.
• Each object inherits from another object.
• Objects are mutable.
• Objects get their own variable context when they’re created.

Creating Objects:

Syntactically speaking, there are several ways to create an object in JavaScript. But no
matter how you create an object, it’s actually abstracting an underlying API
called Object.create() .

In some instances there’s good reason to use Object.create() directly, but we won’t
cover that here. Instead, let’s look at more common ways to create objects.

Object literal notation is declarative in nature. The object bike in this example has three
members: the gears and currentGear properties and the changeGear function. To reference
those members once the object has been created, use dot notation.

Literal objects are great for one-off objects. But if you want to create two or more objects of
the same type, they are not practical. For that, you need repeatable logic to create new
objects.

New Objects with Constructors –


Another way to create objects is to use a constructor. A constructor is a function that
contains instructions for establishing the properties of an object when that object is created
and assigned. This has an advantage over object literal as you can create many instances of
objects that have the same properties.
In this example Bike is a normal JavaScript function that defines the object. We follow
JavaScript convention and capitalize the first word to signal that this function is a
constructor. The new keyword is critical. Without new , the this pointer will not point
to the object you expect and causes unintended behavior. We revisit this when we
cover context in a later unit.

Notice the assignment of the changeGear function is done using something


called prototype . This ensures the function is defined once and shared by all instances
created from this constructor. We cover use of prototypes and inheritance later in
this unit.

Syntax-wise, object literal notation and constructors are pretty different. But in each
case you still end up with a new object created in memory, with the variable bike as
a pointer to that object. With the constructor, you can make lots of Bike objects with
the same properties and functions.

Assigning Properties and Functions to Objects

If you understood from the bike examples above that there are two possible types of
members in an object—properties and functions—you would be correct.

Properties come in three basic shapes.

• Primitives
• Objects
• Arrays
At the time of the writing of this module, there are seven primitive types in
JavaScript: string, number, Boolean, null , undefined , symbol, and bigint.

Primitive types are immutable. When a variable is a primitive type, it’s passed by
value when assigned. That is to say, each time a primitive is assigned, a copy of the
value is made and assigned to the new variable.

Pretty much anything that isn’t a primitive in JavaScript is an object. In object literal
notation, object properties are denoted by curly brackets.

Arrays themselves are also implemented as objects in JavaScript. Arrays can be


created with the Array() constructor function or with literal notation denoted by
square brackets.

Functions have their own unit in this module, so we won’t talk about them here, but
based on the above, let’s take another pass at defining a more complex bike object
using object literal notation.

Referencing Properties by Bracket Syntax - Referencing an object member is most commonly done
with dot notation: bike.frontGearIndex

In dot notation, there are strict rules for the names of properties. However, JavaScript also
allows for another syntax called bracket notation. The members above would be referenced
as follows in bracket notation.
Bracket notation has two benefits. You can name your property or function anything you
want, and because it’s a string, you can pass a property or function name through a variable
and call it.

Object Mutability:

Objects in JavaScript are mutable, which means that if you want to modify the shape
of an object, you can.

Let’s take the bike object we created. We could, for instance, add a new property or
function. Even though you may not have access to the code where the object is
initially defined, you can modify the shape of your object once it’s in memory. The
important point, though, is that only one instance of the object changes. Let’s look
back at our Bike constructor:

Objects and Inheritance

Despite not having classes as defined by classical languages, JavaScript still has an
inheritance model, called prototype inheritance.

A prototype is another object. It sits in memory, and defines properties or functions


that other objects inherit if they share the same prototype.

Traditionally in JavaScript objects share the same prototype by sharing the same
constructor function. Remember the Bike constructor. We assign
the changeGear function to something called prototype .
This way every object created from Bike inherits the changeGear function.

Classes and JavaScript

The class keyword in JavaScript is a nice bit of syntactic sugar to address the
complexities of prototype inheritance using constructor functions. Under the covers,
the engine is still using Object.create and there is still no class (in the object-oriented
sense), just that in-memory prototype object that is the actual source of inheritance.
The good news is that it does read a lot more like code from Java or C#, with a few
JavaScript-specific things to take into account.

An important feature is that functions and attributes automatically belong to the prototype
chain without having to directly reference Object.prototype. This also simplifies creating
multilevel prototype inheritance.
Lightning Web Components and Objects

Classes and Lightning Web Components

Lightning Web components take advantage of many of the modern improvements to


JavaScript, most notably, the use of class syntax. Components are typically defined by
a JavaScript class that extends another class called LightningElement. Here’s what it
looks like:

The functionality of a Lightning web component is defined in a JavaScript class. This


example also uses some syntax we haven’t addressed yet regarding modules
( import and export ).

• You should avoid defining a function in an object literal.

Lesson 4: Take Action with Events and Functions:


With JavaScript in the browser, events are all over the place. Parts of the DOM emit
events that correspond to what that DOM object does. Buttons have click events,
input and select controls have change events, and virtually every part of the visible
DOM has events for when the mouse cursor interacts with it (like passing over it). The
window object even has event handlers for handling device events (like detecting the
motion of mobile devices).

To make something happen in a web page, functions get assigned to these events
as event handlers.

- DOM events and other events related to the browser environment are not actually
part of the core JavaScript language, rather they are APIs that are implemented for
JavaScript in the browser.

When an event is emitted, a message is created in the engine. It is these messages


that are placed in the event queue we talked about earlier.
Defining and Assigning Functions

In JavaScript functions are essentially special objects. As objects, they are first-class
members of JavaScript. They can be assigned as the values of variables, passed into
other functions as parameters, and returned from functions.

There are two essential phases in the life of a function: definition and invocation.

When function is declared, its definition is loaded into memory. A pointer is then
assigned to it in the form of a variable name, parameter name, or an object property.
It should be no surprise, however, that there are several different syntaxes to do this.

Function Declaration

A declaration is a statement that uses the function keyword to create a function. In


fact, we’ve seen it already when we were looking at our object constructor. That
constructor is a function. But constructor functions are a bit special, so let’s step back
and talk about plain old functions and see how they
work:

In this code sample, function is followed by the name of the function, with
parameters enclosed in the parentheses.

This works fine, but there’s some implicit stuff happening. First of all, the function
name becomes the variable name. It also implicitly assigns the variable to the
enclosing context. Finally, you can call this function before it is declared, such as
below where calculateGearRatio is invoked the line before the declaration.
Function Expressions

Function expressions accomplish the same thing as declarations more


explicitly.

(Skipped things you learned in JavaScripts)

Events and Functions in Lightning Web Components:


The key code artifacts of a Lightning web component are a JavaScript module, an HTML
template, and a CSS file. The only one of these that is required is the JavaScript module
(mind the .xml file which is also required is not code, but metadata about the component).

Functions in Lightning web components most often come in the form of methods
that are members of the class exported by the component’s JavaScript module.
These functions can be event handlers or other functions invoked downstream from
there.
The HTML template references handler functions in a way that resembles static HTML
binding, but in fact it's different. Because the template is compiled into a JavaScript
artifact, the static-looking binding is in fact just a syntactic convention the framework
uses for invoking addEventListener sometime in the lifecycle of your component.

This markup in the template shows event handler binding.

Lesson 5 Learn About Context, Scope, and Closures:


In JavaScript the availability and visibility of variables is referred to as scope. Scope is
determined by where a variable is declared.

Context is the state of the current execution of code. It is accessed through


the this pointer.

(Skipped things you learned in JavaScripts)

The Function.apply() , Function.call() , and Function.bind() functions provide ways to


invoke a function while explicitly binding it to a different object context.

The Global Object:

When JavaScript is executed without any containing object that you write as a
developer, it runs in a global object. For this reason, functions invoked there are said
to be running in the global context, which means that accessing this will point
there.

In a browser, the global context is the window object. You can test this easily by
running the following in your browser developer tools.

this === window; // true


In the increment example, assigning the increment function to
the newIncrement variable moves the context where it is invoked: to the global object.
This is easy to demonstrate.

When we attempt to assign to this.aValue with the new context, the mutable nature of
JavaScript objects comes into play. A new uninitialized aValue property is added to this .
Performing math on an uninitialized variable fails, thus the NaN value. But we can see
that aValue exists on window , and is indeed a number.

Context with Your Objects

In the increment example, as long as the increment function is invoked using obj with
the dot notation, this points to obj . Or, generally speaking, when calling a function
as someObject.function() the thing to the left of the dot is the context in which that
function is invoked.

Think about the Bike example. The Bike constructor defines several properties with
the this reference. It also has functions assigned to its prototype that
reference this .

We then call Bike with the new keyword.


This looks like we’re invoking the Bike constructor in the global context. However,
the new keyword shifts the context (and the this pointer) to the new object on the
left side of the assignment.

When we invoke any of the functions they are now members of the bike object, so
they use that as the containing context.

The class syntax in JavaScript forces you to invoke a constructor with


the new keyword, so you can’t misdirect your context.

Closures:

When a function is declared, it holds a reference to any variables or arguments


declared within it, and any variables it references in the scope that it is contained
within. This combination of its variables and arguments along with local variables and
arguments from its containing scope is called a closure.

Consider this function, and the function it returns.

When greetingMaker is invoked, we might normally imagine its greeting argument to


last only for the life of it being called.
But the returned function keeps a reference to the greeting argument
in greetingMaker ’s scope. So that finally when it is invoked
through greetingHello / Bonjour / Ciao , it’s still accessible.

Lesson 6 Write Asynchronous JavaScript:


The engine has a single thread that does work, finishes, then has new work stuffed
into it to start over again.

Of course, it’s critical that the thread not be blocked.

If you load this HTML page in your browser, you find that the alert pop up displays
first and then blocks the display of the HTML. This is because the alert() function
halts execution of the JavaScript thread until the user dismisses it. In short, when
JavaScript blocks your browser, it is never a good user experience.

The good news is, apart from a few legacy bits that linger like the alert() function
above, JavaScript is an asynchronous language.

Asynchronous JavaScript Is Everywhere

Let’s revisit events and functions. Previously we looked at some HTML and JavaScript like
this.
In this example we added handleClick as an event handler to the click event emitted
by the button.

And there! We’ve already written some asynchronous JavaScript.

When the event fires, all that happens is a new message is added to the queue. No
event has the ability to take over the thread. Each event fired must get in the queue
and wait its turn to run.

One way to illustrate this is by using the setTimeout function. In this example,
invoking setTimeout , we pass an event handler and a timer in milliseconds. When the
timer is up it fires, adding the event handler to the queue.

Another common mistake is to think the timer is an exact predictor of when the event
handler will fire, but it isn’t necessarily. The event handler still has to wait its turn in the
queue. By measuring time, we can see this in action.

The time is set to one second, and it runs pretty close to that. But clearly there is
some variance in how quickly the function can be added to the queue and then run
each time it’s called.

Now that we’ve seen some examples of asynchronous calls, we can look at some
common asynchronous patterns and constructs.
Callback Pattern:

(Skipped things you learned in JavaScripts)

Promising Stuff:
Promises developed as libraries to handle asynchronous code in a way that made it easier to
reason about when your code succeeded or failed. They also contain built-in mechanisms to
chain one call after the other. Competing libraries eventually standardized in the browser as
the Promise object. Let’s morph bike one
more time.

First, the updated changeGearAsync function takes in the data we pass it and returns a
new Promise object. We pass in a single argument: a callback function that itself has
two functions passed to it, resolve and reject .

When implementing a promise you perform whatever calculations, requests, and so


on that you want in the callback function. Once done, if all’s right with the world, you
invoke resolve with the data you want to pass back. If you encounter problems you
signal that to the function caller by invoking reject along with any relevant errors as
the argument.
Now we have something a lot easier to reason about. If changeGearAsync works,
the then function is invoked with the function passed into its argument. If it does
not, catch is invoked.

If the callback function itself returns an instance of Promise , that’s when things get
exciting. You can simply chain those two promise functions together. For instance, if
we want to change both the front and rear gears.

The changeBothGears function above shows us chaining two calls to changeGearsAsync ,


each with the object that corresponds to either the front or rear gears. After calling it
the first time, we call it again at the end of the first then . Another then can be tacked
onto that. Fundamentally, each time a then returns a promise, it can be followed with
another then until we’ve exhausted all chained actions.

Async/Await

Before signing off, it’s worth mentioning some newer additions to the asynchronous
arsenal: the async and await operators. These build on promises, allowing them to
be used in a way that much more closely resembles synchronous JavaScript.
Lightning Web Components and Asynchronous JavaScript - Interacting with Salesforce:

Lightning Web Components enables the developer to make use of both promise-
based asynchronous functionality and the async/await functionality.

There are several features implemented in Lightning Web Components that use
asynchronous JavaScript. Most of these revolve around interaction with the server.
One example is the way an Apex method can be invoked imperatively in a Lightning
Web Component.

Here is how you would invoke it using a promise-based API:

When we call import findContacts… this is standard module syntax to include the
functionality of another module in this component. We surface the findContacts Apex
method here as a JS function of the same name.

When we invoke it in the handleSearch() function, the parameters for the Apex
method are passed as a literal object, and then we see the familiar promise-based
syntax of a then and a catch function.

Part 2 - Modern JavaScript Development - Module

Lesson 1: Get Started with Modern JavaScript Development:


This module is here to help you make sense of modern JavaScript development and get you up to
speed as quickly as possible. 😊 LESSSSSGOOOOOO!

{JavaScript history in theory} - All of a sudden developers realized that JavaScript was more
than just a scripting language to play around with. Developers began to see it as something
that they can use to put together complex web applications.

Not all major web and mobile browsers support the latest ECMAScript release. Even though
there are ways around browser limitations using transpilers and polyfills, these introduce
more complexity and can cause performance issues.

The good news though - browsers are finally catching up, and many of the ES6 features that
were once available only with the use of a transpiler such as Babel or Traceur are now good
to go in the latest versions of major browsers, such as Google Chrome. YaY!~

To find out which features are supported by which engine type, go


to http://kangax.github.io/compat-table Don’t worry about the chaos - by default, this page
shows you the compatibility table for ES6 features. You can see this in the top bar.
Notice how the 6 is highlighted? This means that you are seeing what's compatible for ES6. If
you wanted to see what was compatible for ES5, you would select the 5. To see what is
compatible for ES2016 and above, select 2016+. You get it.
The most important thing to observe here is that right above the Current browser column is
a percentage
Green = Supported in the current browser
Red = Not supported in the current browser

Using a Code Playground:

1. n your Google Chrome browser, navigate to https://playcode.io/.


2. Click Open Editor.
3. Select Empty JavaScript from the templates.

Lesson 2 - Explore New Syntax in JavaScript ES6:


Function vs Block Scope

Variables declared with the var keyword are said to be in the function scope. This
means that a variable would only exist within the scope of the function in which it
was declared. Or the nearest parent function, if it's a nested function.

That makes sense. And it still makes sense when you consider global scope, in which
a variable is declared outside of a function. Take, for example, the following code.
You should see both 1 and 2 in the console. First 2 and then 1. Because of function
scope, 2 is printed when the function is called. And because of global scope, 1 is
displayed the second time, when the variable is written to the log outside the
function.

Most developers get this, and everything is great until they encounter code
containing an if statement, such as this example.

Executing that code results in the number 2 appearing twice, because the fact that
the var keyword does not support block scope. A block is any code within curly
braces. Block scoping ensures that any variables defined within those braces don't
become global variables. They instead have local scope. Having this type of control
over how variables are scoped helps you prevent unexpected behaviour in your code.

Let Is the New Var:


Variables assigned with let are always block scoped. But this isn't the only benefit to using
the let keyword. Variables assigned this way also cannot be hoisted.

Hoisting occurs when the JavaScript interpreter makes two passes at your code. In the first
pass, variable and function declarations are “hoisted” to the top of the code. And in the
second pass they are evaluated and assignments are made. If only we had a nickel for every
time that poorly understood behavior has caused a bug.

many JavaScript developers now use let almost exclusively. And we suggest you do too.
Using block-scoped variables is not only less error-prone, but makes it easier for other
developers to know how a variable was meant to be scoped.
And There's Also Const
Useful when you need to declare a variable that cannot be redeclared or reassigned.
Essentially, it's read-only.

However, there are a couple of things to be aware of when using the const keyword.
Since const values cannot be reassigned, they must be initialized at the time they are
declared. If you tried to execute the following code, you would get an error telling
you either unexpected token or that it was missing an initializer in
the const declaration.

• Constants are not immutable. This means that it is possible to modify the
properties of objects or arrays assigned with const . For example, if you
declare an object such as this:

*** Don't forget that when dealing with objects or arrays, only the object itself cannot
be reassigned. Properties within that object or array can be changed.

Why Type the Same Thing Twice? – Shorthand coding


1)
All we did here was remove the repeating variable names and colons ( : ).

2) A simpler way of getting data out of arrays or objects

The brackets on the left side of the assignment are part of the new destructuring
syntax. So, this code is the same thing as saying, “Give me four variables named one,
two, three, and four, and assign the first value in the numbers array to variable one,
the second value to variable two, and so on.” Shorter, sweeter, great.

But now let's say that you want to get just the third value, and you are not really
interested in assigning variables to the first two elements. You can still use this
syntax:
A Better Error Message

(Skipped things you learned in JavaScripts) ${___}

Lesson 3 - Understand JavaScript Functions:


The Trouble with This
(Skipped things you learned in JavaScripts) Functions

Better Parameter Handling


(Skipped things you learned in JavaScripts) Functions

Two Uses for the Same Thing? ... Three dots Operator

The three dots ( ... ) operator has two uses. As the rest operator, it is used to gather up all
the remaining arguments into an array. But as the spread operator, it allows an iterable such
as an array or string to be expanded in places where zero or more arguments or elements
are expected, or an object to be expanded in places where zero or more key-value pairs are
expected. It is just either expanding or collapsing that iterable. Arrays can be spread into
objects but objects can't be spread into arrays.

Lesson 4 - Work with Classes:


If It Looks Like a Class…
Prior to ES6, if you wanted to create a class in JavaScript, you used prototypes to do
something similar to this:

In that example, a prototype-based constructor function named Animal was created. An


uppercase “A” was used in the function name and arguments were assigned to
the this keyword. This is the only clue that lets other developers know that Animal is not
just another function. If you wanted to instantiate the class and call the printName function,
you would do it like this:

In an attempt to make JavaScript at least appear to work like a class-based language, ES6
introduced the class keyword. Using this new syntax means that the Animal class can now
be defined like this:

What is important to know is that even though the class keyword is used, the underlying
object created is still a function. Executing the following code would show “function” and not
“class” in the console as the type.
Instantiating and using methods from the class works almost the same as it did for
constructor functions. Using the new keyword was optional for ES5 constructor
functions, but now it’s required. If you try to leave off the new keyword when working
with classes, a TypeError will be thrown.

Another difference is that you can call a function that has yet to be declared. Classes
do not allow this sort of thing. A class can only be accessed after its definition is
evaluated.

• Classes can contain the following kinds of members: Constructor, Static Methods,
Prototype Methods, Getters and Setters.

Classes are NOT traditional object-oriented classes


Speaking of Inheritance
Classes come in two flavors: base classes and derived classes. The difference is
the extends keyword. Derived classes (also known as subclasses) have them, and base
classes don't. Take, for example, the following base class named Parent .

Assume you needed to create a subclass named Child that extends the functionality
available in the Parent class. It might look something like this: (Copy below the previous code)

The extends keyword in the Child class definition tells you it's a derived class.

Also notice the use of the super keyword, which allows you to reference the parent
constructor and the method definitions from the base class. Whenever you see
the super keyword, you know you are in a derived class and referring to the base
class.
Tell Me More

• Although commas are used to separate method definitions in objects, they are
not allowed in classes.
• Classes can also be defined using expressions:

And the printName method can be accessed like this:

Lesson 5 - Organize Code with Modules:


The Need for Better Modules
Modular programming involves breaking your code up into logical chunks so that it's easier
to access. Using modules generally results in code that is easier to read and maintain.

ES6 introduced a long-overdue native module system. But it was separate from all the other
ES6 functionality and for a long time, no major browsers supported it. However, that's finally
changed and now most browsers allow you to load ES6 modules with
the type="module" attribute on the HTML5 script tag.

Module Basics - export and import statements.


Modules are pretty simple to create and use. An ES6 module is essentially just a file
containing some JavaScript. Everything inside the module is scoped to that module only. If
you want to make something—like a function, a variable, or a class—available somewhere
else, you need to use an export statement. You then use an import statement to specify
what you want to use from the exported module.

Example
Different Ways to Use Modules - But what if you wanted to rename the functions and
variables and use different names? You can do this using an alias!

The previous code (The one from before)


You can change the variable name in the code by declaring the variable name ‘as’ a new (variable)
name, Like so!: (using the as keyword)

*If you try to use the msg1 variable name you get a reference error

Check this:

Change the variable name in the printMsg!


It's All in the Name – What is ACTUALLY Exported?!
Just the name gets exported!

If you export a variable and then try to change the value in the imported module, you get an
error. Essentially, it's read-only.

The thing to remember here is that you are not allowed to reassign the exported value. It can
only be changed from inside the module it was exported from.

• Modules always execute in strict mode, which means that variables need to be
declared.
• They only get executed once, which is right when they are loaded.
• Import statements get hoisted, which means that all dependencies will
execute right when the module is loaded.
• To access an exported variable that was imported as a single object – Use the
keyword to assign an alias AND reference the alias and property name.

Lesson 6 - Write Asynchronous JavaScript:


Avoiding the Pyramid of Doom – Using Callback function
JavaScript is single threaded, which means that only one function can run at a time.
Therefore, coding in JavaScript inevitably means working with asynchronous code. This is
especially true when you need to do anything that involves I/O (input/output). Like getting
data from a database, making a call to an API, or even just waiting for input from a user.
Because any functions that do these types of things will undoubtedly block the browser.

Using callback functions was one of the ways you did this in JavaScript. A callback is just a
function that executes after another function has finished executing. For example, if you were
to run the following code in PlayCode and then look at the Console, you would see the
message, "1st Call".
it would take 1 second or 1000 milliseconds for that to happen since
the doSomething function uses the browsers built-in setTimeout method to simulate a
delayed response. This kind of code works fine and most developers can understand it. But
what happens if you want to call this function multiple times, but only after the previous call
finishes? And what happens if one of those callback functions fails?

The pyramid of doom is typically used to identify asynchronous code that is deeply nested,
which tends to result in a pyramid-looking shape. Basically it's code built from several
dependent asynchronous functions that can all potentially have errors. Trust us, code like this
can get real messy, real quick. – AVOID THIS!

A Promise Is a Promise – Promise Pattern - to return something at a later time

A promise is just that: a promise to return something at a later time. Either the thing you
wanted is returned, or an error. ES6 introduced promises natively to JavaScript in the form of
a Promise object and they are based on the Promises/A+ open standard and offer many
advantages to traditional callback functions. The most important advantage is how easy it is
to chain asynchronous functions together.

Let's start by rewriting the doSomething function so that it uses ES6 promises.

The actual doSomething function, now returns a new Promise object. And instead of calling
the callback , the function now calls resolve .

The cool thing here is how the doSomething function is called. We can now use
the then method to specify what gets called only after the first function completes. Running
this code should result in three messages displayed in the Console, "1st Call" followed by
"2nd Call" and then "3rd Call".

Making the code shorter with arrow functions:


And to see what happens when calling the reject method, we need to add some code in
the setTimeout handler that intentionally throws an error.

Notice that we added the catch method to the very end of the call and if triggered, the error
object is returned. To print out the error message, we need to specify the message property
name.

• calling the error function at the bottom of the chain using the catch method is a best
practice since it catches all errors produced from the chain.
Another Way to Await and See - async functions
The ES2016+ release introduced async functions and a different way of calling native
promises. The structure of the promise remains the same, but what changes is how the
promise is called. The call is wrapped in a function that uses the async and await keywords.
What is returned is a promise object that contains either the resolved or rejected value. For
the doSomething function, the call looks like this:

Tell Me More

• The Promise object includes four methods that you may want to check out for
more advanced promise scenarios. They include:
o Promise.all(iterable)—Returns promise only after all the promises in
the iterable have resolved or any are rejected.

If the returned promise resolves, it is resolved with an aggregating


array of the values from the resolved promises, in the same order as
defined in the iterable of multiple promises.
If it rejects, it is rejected with the reason from the first promise in the
iterable that was rejected.

o Promise.race(iterable)—Returns promise after the first promise in the


iterable has resolved or rejected.
o Promise.resolve(value)—Returns promise that is resolved with the
value passed in as a parameter.
o Promise.reject(reason)—Returns a promise that is rejected with the
reason passed in as a parameter.
• If you have ever had to do a JavaScript data request using XMLHttpRequest,
then you know it is not a particularly easy thing to do. The Fetch API allows
you to do this with much less than code and as a bonus it returns a promise
object. It is the perfect companion for native ES6 promises. You can learn
more about it from the links in the Resources section.
• Good job! :)

Lesson 7 - Test Your JavaScript: - (Jasmine ad)


Always test your code, for bugs, errors etc.

Behavior-Driven Development

Behavior-driven development (BDD) is a process that was born out of Test-driven


development (TDD). BDD involves organizing tests such that their behavior is tested,
rather than their implementation. When designing these types of tests, think, “How
can I describe, in sentence form, what this code does and what I should expect from
it.”

You then use a behavior-driven tool to create a test script. The script should contain
natural language sentences that essentially describe what the test is supposed to do.
It should also contain assertions to see whether the test is working.

Which Tool Should You Use?

One of the more popular behavior-driven tools is the easy to use – Jasmine.

In Jasmine you use a describe function to create a test suite, but you're really just
creating a JavaScript function. Inside of that function, use the it function to specify
one or more specs (or tests), which are also just functions. Inside of the spec function,
put assertions to check whether the test worked.
Jasmine includes global functions ( beforeEach and afterEach ) that can be used to execute
code before and after each of your test specs have run. This is useful for when you have set
up and tear down code that requires a lot of resources, like logging in and out as a certain
user. There are also beforeAll and afterAll functions, but these are run only once for each
describe block they are part of.

Using the Jasmine Testing Framework

he installation page for Jasmine provides a few different ways to install it. You can
also run it stand-alone by downloading the latest version from the GitHub repo and
then copying and unzipping the entire contents of the lib folder to your JavaScript
project directory.

Once you have written your JavaScript test suite, you can reference this, along with
the necessary Jasmine framework files from an HTML page to run the tests in your
browser.

To see how it works, let's assume you want to create a Jasmine test suite to test the
Parent/Child class code you saw in the Working with Classes unit. In case you don't
remember, the code for the Parent class looked like this:
Once you've downloaded and extracted the Jasmine lib folder, create a new folder on
your local machine. Copy the lib folder you extracted into the folder you just created.
This is also where you place the JavaScript code you want to test, which in this case is
the parent and child classes.

You can add the JavaScript code for the Jasmine test suite to a separate file. It might
look something like this:

The only thing left to do is to create a simple index.html file that loads all the required
Jasmine files, along with your JavaScript files. That markup code might look something like
the this:

You might also like