Home > Article > Web Front-end > JavaScript uses closures to achieve modularity
Take advantage of the power of closures, but on the surface, they don't seem to have anything to do with callbacks. Let’s take a look at the most powerful of them all: modules.
function foo() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { console.log( something ); } function doAnother() { console.log( another.join( " ! " ) ); } }
As you can see in this code, there is no obvious closure, only two private data variables something and another, and doSomething () and doAnother() two internal functions, their lexical scope (and this is the closure) is the internal scope of foo().
Next consider the following code:
function CoolModule() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { alert( something ); } function doAnother() { alert( another.join( " ! " ) ); } return { doSomething: doSomething, doAnother: doAnother }; } var foo = CoolModule(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3
This pattern is called a module in JavaScript. The most common way to implement the module pattern is often called module exposure, a variation of which is shown here. Let's take a closer look at the code.
First of all, CoolModule() is just a function, and you must create a module instance by calling it. Neither the inner scope nor the closure can be created without executing the outer function. Secondly, CoolModule() returns an object represented by object literal syntax { key: value, ... }. The returned object contains references to internal functions rather than internal data variables. We keep internal data variables hidden and private. You can think of the return value of this object type as essentially the module's public API. The return value of this object type is eventually assigned to the external variable foo, and then you can use it to access the property methods in the API, such as foo.doSomething().
It is not necessary to return an actual object from the module, you can also directly return an internal function. jQuery is a good example. jQuery and the $ identifier are the public API of the jQuery module, but they are themselves functions (since functions are also objects, they can also have properties themselves).
The doSomething() and doAnother() functions have closures that cover the scope inside the module instance (implemented by calling CoolModule()). When we pass a function outside the lexical scope by returning an object containing a property reference, we have created the conditions under which closures can be observed and practiced. If you want to describe it more simply, the module pattern needs to meet two necessary conditions.
1. There must be an external enclosing function, which must be called at least once (each call will create a new module instance).
2. The closed function must return at least one internal function, so that the internal function can form a closure in the private scope and can access or modify the private state.
An object with function properties is not a true module in itself. From a convenient observation point of view, an object returned from a function call with only data attributes and no closure function is not a real module. The previous example code has a separate module creator called CoolModule() that can be called any number of times, creating a new module instance with each call. When only one instance is needed, this pattern can be simply improved to implement the singleton pattern:
var foo = (function CoolModule() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { alert( something ); } function doAnother() { alert( another.join( " ! " ) ); } return { doSomething: doSomething, doAnother: doAnother }; })(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3
Call this function immediately and assign the return value directly The module instance identifier foo given to the singleton.
Modules are also ordinary functions, so they can accept parameters:
function CoolModule(id) { function identify() { console.log( id ); } return { identify: identify }; } var foo1 = CoolModule( "foo 1" ); var foo2 = CoolModule( "foo 2" ); foo1.identify(); // "foo 1" foo2.identify(); // "foo 2"
Another simple but powerful variation of the module pattern is to name it Objects returned as public APIs:
var foo = (function CoolModule(id) { function change() { // 修改公共API publicAPI.identify = identify2; } function identify1() { alert( id ); } function identify2() { alert( id.toUpperCase() ); } var publicAPI = { change: change, identify: identify1 }; return publicAPI; })( "foo module" ); foo.identify(); // foo module foo.change(); foo.identify(); // FOO MODULE
A module instance can be modified from within by retaining an internal reference to the public API object inside the module instance. This includes adding or removing methods and properties, and modifying their values.
The above is the entire content of this article. I hope that the content of this article can bring some help to everyone's study or work. I also hope to support the PHP Chinese website!
For more articles related to JavaScript using closures to achieve modularization, please pay attention to the PHP Chinese website!