📣 Attention Salesforce Certified Trailblazers! Link your Trailhead and Webassessor accounts and maintain your credentials by December 14th. Learn more.
close
trailhead

Learn JavaScript Core Concepts

Note

Note

A Quick Disclaimer: This module assumes you’re familiar with fundamentals of JavaScript such as basic keywords, operators, and syntax but still relatively new to the language. If you’re coming from a classical programming language (such as Apex) to JavaScript, this module is for you! Its purpose is to help you understand the what and the why of certain features of JavaScript so that you can write better code in Lightning components, and perhaps other JavaScript frameworks. 

Learning Objectives

After completing this unit, you'll be able to:

  • Describe the nature of the JavaScript runtime environment.
  • Distinguish between the JavaScript engine and the language.
  • Avoid key pitfalls when learning JavaScript.
  • Describe some important JavaScript best practices.

The What, Why, and How of JavaScript

In the early 2000s, the software world was exploding with the idea that you could build applications that were hosted and delivered entirely over the Internet. Although we take web applications for granted now, at the time they were as mind-blowing as seeing a robot ride a bike. 

Robot riding a bike.

Browsers were simple HTML renderers, and HTML and JavaScript standards were fragmented. To create a web page with even mildly complicated functionality, you had to force users to use only one browser, usually Internet Explorer. Even today there are apps that force this because of design decisions made in this era. 

To work around some of these limitations, server-side UI frameworks evolved to allow software developers to dynamically create web pages on servers. Complex logic executed where the computing power was: on the server. Rendered HTML was then served to the feeble browser. In this world, JavaScript was primarily a way to make 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. 

Fast forward to the present and the world is a different place. Browsers are powerful applications that optimize web page viewing. 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 frameworks tend to be client-side rendered. In Salesforce, this is done with the Lightning component framework. But for many developers, writing Lightning components is still new. 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. 

Time to level up your JavaScript skills. 

The JavaScript Runtime

The JavaScript runtime is an engine that interprets JavaScript code. It can be part of a browser, or other runtime environment like a server. Modern JavaScript engines are sophisticated and powerful to optimize execution and designed to conform to the ECMAScript standard. 

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. 

JavaScript engine with the stack, queue, events, and APIs

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. 

The event loop takes work from the queue and passes it to the stack

This is, of course, a simplification, but illustrates the basic model of how the JavaScript engine gets its work done. The JavaScript language works the way it does in practice because of this architecture. 

JavaScript the Language

As a language, JavaScript is frequently misunderstood. If you’ve picked it up for any length of time, you’ve undoubtedly asked yourself questions. Is it a scripting language? What does it have to do with Java? Is it a real programming language? Why does it do that

Let’s set some context around JavaScript as a language to help you answer some of those questions. 

JavaScript Is Changing

Because JavaScript is built according to the ECMAScript standard, it’s constantly changing. An update to the standard describing new features is published every year, then JavaScript engine projects (browser and runtime manufacturers) put them in place. 

Updates can include more modern language features as JavaScript matures. In other cases features are added to implement cleaner syntax for existing functionality (these are called syntactic sugar). 

Adoption of APIs Is Not Universal

This statement may seem scary, but the vast majority of JavaScript APIs work in the most common browser platforms. Still, implementers don’t adopt every language feature or API at the same rate. Some never adopt certain features (although this is rare). In general if you want to use a newer feature of the language, you should understand how well it will work in your target browser(s) using a resource like caniuse.com

If a new feature isn’t implemented natively, there’s often a bit of code written to temporarily serve the purpose of that missing feature. This temporary fill-in code is called a polyfill. In fact, Lightning components use a curated list of polyfills that are applied before other code is run to automatically improve browser compatibility.  

Indispensable Things to Know

It’s time to look at some code. Let’s start with some things every JavaScript developer should know to make their lives easier. 

Remember Case Sensitive

JavaScript is case sensitive. This is tricky for many Salesforce developers who are used to both Apex and SOQL being case insensitive. Remember anytime you write JavaScript code in Salesforce, be mindful of case sensitivity. 

Declaring Variables

Variable declaration is done using one of three operators: var, let, and const. In general use let and const. The table below summarizes the functional difference between these three keywords. 

Keyword
Scope
Mutable Assignment
var
function
yes
let
block
yes
const
block
no

Scope is a topic that we discuss later, so let’s address what mutability means. 

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. As is often the case, this is best understood by demonstration

Note

Note

JavaScript playgrounds are a valuable tool to try out code, and see how it works live in realtime in your browser. There are plenty of JavaScript playgrounds, but in this module, we’ll link to examples in jsbin.

//primitive assignments
var myBike = "Mountain Bike";
let currentGear = 5;
const numberOfGears = 12;
//reassignment
myBike = "Penny Farthing"; // this works
currentGear = 1; // so does this
numberOfGears = 1; // error

Above, myBike and currentGear had no problem when being reassigned values. But when attempting to do so to numberOfGears, there is an error. 

When working with objects (rather than primitives), 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 as seen below. 

// call constructor, new object, assign it to bike 
const bike = new Bike(); 
//Change internal state by calling a function 
bike.changeGear("front", "Up"); 
// add a new member to bike that did not exist before 
bike.type = "Penny Farthing"; 
// check for success 
console.log(bike.calculateGearRatio()); // 4.0909... 
console.log(bike.type); // "Penny Farthing" 
// attempt to point bike to new instance of Bike 
bike = new Bike(1,2); // error

Here, we create an object from the Bike constructor and assign it to the bike variable (remember, case sensitive). We can then change anything we want about it such as calling functions that change its state and even adding new members. But the moment we attempt to reassign bike to something else, in this case by calling the constructor again, there’s an error. 

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: 

let num1 = 9 * "3";
console.log(num1); // 27 (a number)
let num2 = 9 + "3";
console.log(num2); // "93" (a string)

In the first example the * operator can only be used for math operations, coercing the string "3" to a number. The outcome is 27. In the second, the + operator sees the string "3" making it a unary operator (concatenate). This coerces 9 to the string "9" with an outcome of the string "93"

At first glance this can seem handy, but in practice can lead to confusing results. 

Don’t Use Implicit Type Coercion

Many instances of implicit type coercion are confusing. For instance Boolean comparisons. The ==  and != comparison operator common to C-family languages will attempt to convert anything to Boolean. There are deterministic rules, but they are too complex to be practical. Here are some fun examples.

false == ""; // true
false == "0"; // true
"" == "0"; // false
[0] == 0; // true

“Why did that do that?” 

Exactly.

For Boolean comparison the best practice is to use === and !==. With these operators, primitive types are only equivalent when both type and value match, and object comparisons are only true when the their respective pointers are pointing to the same memory address. Trying the same comparisons as above: 

false === ""; // false
false === "0"; // false
"" === "0"; // false
[0] === 0; // false

Truthy and Falsy

You know that rule we just laid out warning against implicit type coercion? Well, here’s the exception. 

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)

false is false (of course!). The rest of these values are coerced to false. As a group they are referred to as falsy

There’s no question that true is just that—true. But any other value of any type is coerced to true. We call these values truthy

This has a handy side effect. Let’s say you want to test for several types of invalid data by simply passing a variable into an if expression. 

const myRecord = response.getReturnValue();
if (myRecord) {
  //now process the record
}

If for some reason the above assignment fails and we end up with an uninitialized variable (undefined), an empty string, or 0, we’ve covered all those bases just by doing the conditional check on the myRecord variable. This is a widely accepted practice in JavaScript. 

this Is Tricky

This module has an entire section about how to use the this pointer. It 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: 

public class MyApexClass {
  private String subject;
  public MyApexClass(String subject) {
    this.subject  = subject;
  }
}

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. 

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. 

This can be a bit shocking if you haven’t worked in a language where functions aren’t first-class citizens, or that uses lambdas. We spend a whole unit just on functions later on. 

More on that—and so many other things—later. 

For now, you have a good basic introduction to JavaScript concepts. Next we look at how JavaScript works in the browser. 

Resources

TrailheaDX Session: JavaScript for the Salesforce Platform, A Beginner's Guide

Code Sample Project for This Module

Pluralsight Getting Started with JavaScript in Salesforce 

MDN JavaScript Basics

You Don't Know JavaScript

JavaScript Type Conversion

JS the Right Way

retargeting