This article mainly helps you understand the concept of closure in javascript functional programming. In general, every function in JavaScript is a closure, interested friends can refer to the concept of closure (closure) in functional programming. In 1960s, Scheme was the first language to implement closure, and it is a dialect of LISP. The closure feature is widely used in other languages.
Closures are strictly defined as a collection of functions (environments) and their enclosed free variables ." This definition is a bit obscure to everyone, so let's first illustrate what a closure is through examples and less rigorous explanations, and then illustrate the classic use of some closures.
What is a closure?
In general, every function in JavaScript is a closure, but in general, nested functions are more
The closure feature is shown in the following example:
Var generateClosure = function () {var count = 0; var get = function () {count ++; return count ;}; return get ;}; var counter = generateClosure (); console. log (counter (); // output 1console. log (counter (); // outputs 2console. log (counter (); // output 3
In this Code, the generateClosure () function has a local variable count, and the initial value is 0. There is also a function called get. get increases the count variable in its parent scope, that is, generateClosure () function by 1 and returns the value of count. The returned value of generateClosure () is the get function. Externally, we call the generateClosure () function through the counter variable and obtain its return value, that is, the get function. Next, we call counter () several times repeatedly (), we found that each return value increases by 1.
Let's take a look at the features of the above example. According to the general imperative programming thinking, count is a variable in the generateClosure function. Its life cycle is the period in which generateClosure is called, when generateClosure is returned from the call stack, the space applied for by the count variable is released. The problem is that after the generateClosure () call is complete, counter () references the "released" count variable. Instead of making an error, counter () is called every time () and returns count. What's going on?
This is the so-called closure feature. When a function returns a function defined internally, a closure is generated. The closed package includes not only the number of returned functions, but also the definition environment of the function. In the above example, when the internal function get of the generateClosure () function is referenced by an external variable counter, the local variables of counter and generateClosure () are a closure. If it is not clear enough, the following example can help
You understand:
Var generateClosure = function () {var count = 0; var get = function () {count ++; return count ;}; return get ;}; var counter1 = generateClosure (); var counter2 = generateClosure (); console. log (counter1 (); // output 1console. log (counter2 (); // output 1console. log (counter1 (); // outputs 2console. log (counter1 (); // output 3console. log (counter2 (); // output 2
The above example explains how closures are generated: counter1 and counter2 call the generateClosure () function to generate two closure instances, the count variables referenced inside them belong to their respective runtime environments. We can understand that when generateClosure () returns the get function, it returns the internal variable (that is, the count variable) of the generateClosure () function that may be referenced by get, A copy is generated in the memory, and the two instances counter1 and counter2 of the function returned by generateClosure () are independent of each other.
Use of closures
1. nested callback Functions
Closures have two main functions: one is to implement nested callback functions, and the other is to hide the details of objects. Let's take a look at the following code example to learn about nested callback functions. The following code uses MongoDB in Node. js to implement a simple function to add users:
exports.add_user = function(user_info, callback) {var uid = parseInt(user_info['uid']);mongodb.open(function(err, db) {if (err) {callback(err); return;}db.collection('users', function(err, collection) {if (err) {callback(err); return;}collection.ensureIndex("uid", function(err) {if (err) {callback(err); return;}collection.ensureIndex("username", function(err) {if (err) {callback(err); return;}collection.findOne({uid: uid}, function(err) {if (err) {callback(err); return;}if (doc) {callback('occupied');} else {var user = {uid: uid,user: user_info,};collection.insert(user, function(err) {callback(err);});}});});});});});};
If you are not familiar with Node. js or MongoDB, you don't need to understand the details. You just need to understand the rough logic. This Code uses the layer-by-layer nesting of closures, and each layer of nesting is a callback function. The callback function is not executed immediately, but is called back by the function of the request after the corresponding request is processed. We can see that there are references to callback in each layer of nesting, And the uid variable defined by the outer layer is used at the innermost layer. Because of the existence of the closure mechanism, even if the outer function has been executed, the applied variables in its scope will not be released, because the internal function may reference these variables, in this way, nested asynchronous callback is implemented perfectly.
2. Implement Private Members
We know that JavaScript objects do not have private attributes, that is to say, every attribute of an object is exposed to the outside. This may cause security risks. For example, if the user of an object directly modifies an attribute, the internal data consistency of the object is damaged. JavaScript uses an underscore (for example, _ myPrivateProp) before all private attributes to indicate that this attribute is private, and external objects should not be read and written directly. But this is just an informal Convention. If the user of the object does not do this, is there a stricter mechanism? The answer is yes, which can be achieved through closures. Let's take a look at the previous example:
Var generateClosure = function () {var count = 0; var get = function () {count ++; return count ;}; return get ;}; var counter = generateClosure (); console. log (counter (); // output 1console. log (counter (); // outputs 2console. log (counter (); // output 3
We can see that only counter () can be called to access the count variable in the closure and Add 1 to it according to the rule. In addition, it is impossible to find the count variable in other ways. Inspired by this simple example, we can encapsulate an object with a closure and return only one "accessor" object to hide the details.
The above is all the content of this article, hoping to help you better understand javascript closures.