Salesforce development is diverse. Beyond coding, the platform offers many declarative tools and solutions that developers work with. Every Salesforce engineer has their own path and different projects. Some of them might have worked mostly on Apex, Flows, or maybe on Lightning Web Component (LWC) development. Salesforce offers such a vast array of technologies that it’s impossible to become an expert in all of them. As a result, even some senior engineers lack experience and knowledge in key areas such as JavaScript (JS) and LWC.
So with that said, we will cover two important concepts in JavaScript that will be useful for all levels of Salesforce Developers. Knowing them will be useful for interviews and designing code better in some scenarios. Additionally, I still see many developers using “var” in LWC. It is important to understand the behavior of “var” in a block scope, which is different from “const” and “let”.
Scopes and Scope Chain
Scope in JS determines the accessibility and visibility of variables, functions, and objects while controlling where can we access them. There are three main types of scopes: global scope, function scope (local scope), and block scope.
Global Scope
Global scope is the outer scope – variables, functions, and objects defined in global scope are accessible everywhere in the code. Let’s take a look at an example:

As you can see global variable is accessible from a function and even from a nested function. As mentioned, variables of global scope are accessible everywhere in the JS file. This is achieved with the help of scope chains – JavaScript creates scope chains in the creational phase of the execution context.
JS engine looks at the code and creates scope chains so it already knows which elements will be accessible where. The scope chain then connects the function scope to the global scope.
However, the scope chain works only one way, not in both ways, which means that elements are accessible from top to bottom. In our case, the global variable is visible to functions, but not the other way around; if we define a variable inside a function, it won’t be accessible in the global scope.
Function Scope
Variables, functions, and objects defined in a function, are available in the function itself and nested (child) functions inside it.

Note: Scope chain does not work the other way around, so parentFunc()
would not be able to access elements of childFunc()
.
Block Scope
Blocks in JS are if, else if, else statements, loops, and switch statements. Block scope behavior is similar to function scope, as an inner block can access elements of the outer block:

We also cannot access variables of a block from another, unrelated block:

Moreover, we would get the same result if we declared the variable with the “let” keyword. But let’s see what happens in the case of using “var”:

Variables declared with “const” and “let” are block-scoped, whereas variables declared with “var” are not. However, “var” is function-scoped. If a “var” declared variable is in a function A, you cannot access it outside of that function.
Closure
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
When the execution of a function is started in JS, it is added to the stack, and when its execution is finished, it is then removed from the stack. The variables inside it are then removed from the memory.
However, with the help of closures, we can retain access to the variables of the outer function from the nested function. This may sound confusing, but it will become clear when we dive into the example and more explanation.

The execution of the parentFunc()
is initiated by: const returnedChildFunc = parentFunc()
. It returns the childFunc()
, and at this point, parentFunc()
is already removed from the stack, and parentVar()
is deleted from the memory. After getting parentVar()
deleted from the memory, we are calling returenedChildFunc()
, which is able to print parentVar()
. Somehow, it can see the value of the variable which was supposed to be deleted from the memory.
That was achieved with the help of the closure – JS engine creates closure in the creation phase before starting to execute the code. JS engine looks at the code and if it sees that there is a reference from an inner function to the variable located in the outer function, it creates closures. In other words, it provides the ability to access the variable of the outer function even when the execution of the outer function is completed.
Closures help us to encapsulate variables and functions together and make them private for use of the specific functionality. Let’s see the example of it in LWC.
Imagine a scenario, in which we want to calculate discounts for different types of purchases in LWC.
Note: The purpose of this code example is to give you more understanding about closures, other aspects are neglected, e.g. variables are hard coded, and errors are not handled. This is just because of simplicity and to focus your attention on closures.
In this example, the hardcoded original price is 1000. You can see from the demo how it changes by clicking various buttons:

When createPricingModule(this.originalPrice)
is called, the execution context of createPricingModule()
is started as part of the creational phase of the execution context. The engine will see that there are references to the variables of createPricingModule()
from nested function calculatePrice()
, so closure will be created and taxRate()
will be reserved in the memory for calculatePrice()
.
createPricingModule(this.originalPrice)
returns an object containing three functions which we are invoking later in the code.
This is obviously a simplified example – you could have multiple variables and functions inside createPricingModule(this.originalPrice)
and more functionality inside doStandardDiscount()
, doPremiumDiscount()
, doWholesaleDiscount()
, and calculatePrice()
functions.
With the help of closures, we achieved a separate module with private variables and functionality. We also achieved something called currying – we can now curry createPricingModule()
and create multiple instances of it for different prices if required.
Summary
Understanding Scopes, Scope Chain, and Closures is crucial for any developer who is working with JS. As mentioned before, Salesforce Developers are not given a chance to have rich experience in every aspect of Salesforce development, due to the diversity of Salesforce. But if you are working or are going to work on LWCs, it is good to have deep knowledge of JS itself.
Closures have many uses, which you can research. In this blog, I explained the core of closure and gave you a use case that should help you understand what closures do – but you can definitely explore more concrete use cases that are solved by closures.
Comments: