Closures build upon the concepts of lexical environments and scope chaining. It is a feature where a function retains access to its lexical scope, even after the outer function has completed execution. This ability enables functions to remember the variables in their lexical environment. Closures allow data encapsulation, preventing direct access to variables while still enabling controlled interaction.
When taskManager is invoked, it creates a lexical environment with a variable tasks initialized as an empty array. The variable tasks is encapsulated within the lexical environment of taskManager and cannot be accessed directly from outside the function.
The returned object contains methods, addTask, listTasks and clearTasks that form closures. These closures retain a reference to the lexical environment of taskManager. This relationship allows the closures to access the tasks array even after the execution context of taskManager is removed from the call stack.