Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

The concept of "Closures" is one of the very few things that are unanimously considered to be "tricky" in the Javascript community. It is especially challenging for people who are new to Javascript. It is also one of the few things for which a mere Google search is not enough to get a gist of.

And get this - As a UI5 Javascript developer, you are most likely already taking advantage of the power of Closures without even realizing it!

So what's the big deal? What makes it such an elusive concept? Why doesn't someone define it clearly? Let's begin by having a look at what happened when someone did try to define it clearly...


"A closure in Javascript is a function or reference to a function together with a referencing environment. A closure allows a function to access those non-local variables even when invoked outside of its immediate lexical scope." - Wikipedia


Okay. While the definition is indeed technically correct, it's certainly not going to help us understand what Closures are. So let us loosen up a bit with the definitions-kind-of-techy-geeky-language and try to understand what a closure is in simpler language. Ready? :smile:

The rest of the post is split into 2 sections :

  1. Bare bones definition
  2. A more practical UI5 example

1. Bare bones definition

Created a function within a function? You've created a Closure!

Let's see a small example of a function defined within another function. It will also help us understand what "referencing environment" in the technical definition means.


//This is our outer function
function showMySecret(password) {
     var secretAnswer = 42;
     var prefix = "The secret is ";
     function showSecret() {
          alert(prefix + secretAnswer);
     }
     //Call our inner function if password is correct
     if(password === "Pass123") {
          showSecret();
     }
}

The "referencing environment" can be understood as a table of name-value pairs that defines the 'environment' or 'context' in which the inner function will run. It is a snapshot of the values of the variables declared within the outer function, that can possibly affect the behaviour of the inner function. The referencing environment consists of...

  1. Formal parameters of the outer function (password)
  2. Variables that are declared within the outer function (secretAnswer, prefix)

This table is created at the time of invocation of the outer function[1] (because the value of the formal parameter wouldn't be known earlier!). So when we invoke our outer function (showMySecret) as follows...


showMySecret("Pass123");

... the environment snapshot will look like this...

All good so far? Great! So now we know what the inner function and outer function look like. We also know what information our 'snapshot table' contains. So what's a closure?


ℹ The inner function and the snapshot table together form the closure.


As we can clearly see, a closure has enough information for the inner function to run, and that too, without depending on the outer function in any way. This is an extremely important point because of the way functions are treated in Javascript. In Javascript, whenever you create a new function, you are actually creating Function objects. And like every other object, Function objects too are eligible to be garbage collected as soon as they have finished executing and are no longer being referenced.

Since our closure contains all the information that the inner function needs to execute, it can be executed even after the outer function is disposed by the garbage collector.

Our first example was intentionally kept simple, so that we could easily arrive at an understanding of what a closure is. Due to its simplicity though, it does not exhibit any of the advantages of having a closure. Its true power will become obvious only when the inner function is invoked from outside the outer function. But how is it possible to have a function defined within another function and yet be invoked from outside? Grab a cup of coffee, and get ready for a slightly more interesting example! :smile:

2. A more practical UI5 example

Our second example (this time in UI5) too is pretty straight-forward. Unlike our first example, this is actually the kind of code that you are likely to come across in productive code. We have a helper method getButton that takes the button text and alert text as parameters, and returns a UI5 button accordingly.

Can you spot the closure here?

Here our inner function is an anonymous function[2] that we create and assign as oButton's listener for its 'press' event. Even though the inner function is defined inside the outer function, it is invoked only when the user clicks on the button - making it a good example of the inner function being invoked from outside of the outer function. If Javascript didn't have the mysteriously wonderful concept of closures, this code wouldn't work! Since the VM[3] will execute only the inner function (which is the event handler) when the 'press' event occurs, and since sAlertText isn't defined anywhere within the inner function[4], this code would fail to work as intended.

But thankfully, Javascript does have closures, and this code does manage to work perfectly. When the 'press' event handler is executed, the handler (the inner function) first looks for a definition of sAlertText within its own body. When it fails to find anything, before losing all hope, it turns to its 'referencing environment' table and looks for sAlertText. Voila! It finds an entry there, picks up the corresponding value and uses it for the alert() statement. So even though sAlertText is seemingly undefined within the function body, the closure knows it all.


ℹ When you invoke a function that is defined within another function, remember that you're dealing with a closure. It remembers the values of variables defined within its outer function. This might not always be desirable though, because the values in the 'snapshot table' might be considered 'stale' or 'outdated' (depending on the scenario) if the inner function is invoked, say, 1 hour after it is created.

Worry not, however - there are techniques and patterns that help you avoid closures too.


If you invoke the getButton() 15 times (to create 15 buttons), you do essentially create 15 closures, and each closure will have its own value for sButtonText and sAlertText according to the arguments that you passed while calling getButton() each time.

[1] : To be more precise, it is created when the inner function is created.

[2] : Anonymous function : Just a fancy name for a function that is defined without a name. In all other aspects, anonymous functions are just like any other function.

[3] : Javascript code is executed within an environment called 'Virtual Machine (VM)'. Every browser comes bundled with a Javascript VM that is used for running the Javascript code that websites contain.

[4] : Assuming that a variable with name sAlertText also doesn't exist in global scope.

3. Conclusion

I told you! You've been using closures without realizing that they even exist, haven't you? However, knowing about them and knowing how they work just might turn out to be crucial in your next debugging-marathon or your next new development. Just sayin'. Also, I really hope are able to take away at least a little learning from this post (Psst. my first blog post!) :smile:

Please comment and share your criticism. Did you find it clear enough? Did I miss anything important? Have you had any (painful/pleasant) experiences with closures?

Fortunately or unfortunately, this was just the tip of the iceberg. Closures may seem to behave 'awkwardly' when they are created inside a loop. Closures are also central to some very important Javascript design patterns. And have you ever seen a "var that = this;" statement in Javascript code? What the heck is that? What happens when you create a function within another function within yet another function!? And how do you make sure you don't accidentally create closures when you don't need them? All this and other UI5 'How-to's - in my upcoming blog posts! Click on 'Follow' to stay updated! :wink:

15 Comments