1. The concept of closures

When we talk about scope, the concept of scope chains, we know that in general variables defined inside a function are not accessible outside the function. But sometimes there is, and there is, a need for closures. Closures are functions that can read variables inside other functions. That’s the concept of closures. Closures allow us to access variables inside one function and inside another.

2. Closure form

Here’s the form of closures, a common way to access variables inside functions.

  • Function 1 returns the value of function
function foo (){ let name = 'xiaom' return function (){ return name } } const bar = foo() console.log(bar()) // The global variable bar gets the internal variable of the local scope foo, which is the most common formCopy the code
  • Inner function assigned to outer variable
let num; function foo() { const _num = 18; function bar() { return _num; } num = bar; } foo(); console.log(num()); / / 18Copy the code
  • 3. Save variables in independent scope by executing the function line immediately (after ES6, let, const is used instead).

Here’s a classic example.

for (var i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, i * 1000); } // The expected output of the code above is 12345 sequentially every second. // According to the event loop mechanism discussed earlier, the timer task is executed after the synchronization task has completed. So I is now 6 and it just prints 5 6's. // The key to solving this problem is to create a separate scope for each loop, so that the operation in the timer can access the corresponding scope variable when executing.Copy the code
for (var i = 1; i <= 5; I ++) {function (I) {setTimeout(function timer() {console.log(I); function (I) {console.log(I); }, i * 1000); })(i)Copy the code

Most of the other forms of closure functions are variations of the above.

3. Pros and cons of closures

Several advantages of closures can be summarized from the above examples

1. External users can access internal variables of functions.
2. Keep the internal variables of the function in memory as follows.
function fn1(){ let count = 0; function fn2 (){ count++ return count } return fn2 } let result1 = fn1() console.log(result1()) // 1 Console. log(result1()) // 2 // Generally, after a function is executed, the function is destroyed along with its internal variables. // The internal variable count of function fn is referenced externally, so the internal variable count of function fn is not destroyed after execution. Therefore, overuse of closures can cause memory consumption.Copy the code
3. Form independent scopes.

Obviously, you can also see from the second point above that overuse of closures can cause page performance problems because they keep function internal variables in memory, causing memory consumption. The solution is to delete unused local variables in time.

4. Applications of closures – Coriolization functions

Here is a typical use of closures: The Currization function. Before we introduce Currization we need to understand the concept of higher order functions.

Higher-order functions are functions that operate on other functions, taking them as arguments or returning them. In layman’s terms, a function satisfying one of the following conditions is a higher-order function:

  • Accept arguments as functions
  • The return value is function

Here is a simple example of using a higher-order function to bind the this pointer to the passed function. He satisfies both conditions.

function foo() {
  console.log(this.name);
}
const obj = {
  name: "xiaom",
};
const obj1 = {
  name: "xiaoh"
}
function bindThis(fn, obj) {
  return fn.bind(obj);
}
bindThis(foo, obj)(); //xiaom
bindThis(foo, obj1)(); //xiaoh
Copy the code

Currization is a special function of higher order, the concept of currization function is introduced below.

Definition: Currying is a technique of converting a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returning a new function that takes the remaining arguments and returns a result.

The definition is very obscure, so let’s modify the above example a little bit.

function foo() {
  console.log(this.name);
}
const obj = {
  name: "xiaom",
};
const obj1 = {
  name: "xiaoh"
}
function curryingFn(fn) {
  return (obj) => {     
    return fn.bind(obj)
  }
}
const newFoo = curryingFn(foo)
newFoo(obj)() // xiaom
newFoo(obj1)() // xiaoh
Copy the code

This changes a function that takes two arguments to one that takes one and returns a function that processes the rest of the arguments. As you can see, the form of the Currization function corresponds exactly to the first form of the closure function. The advantage of currization function is parameter reuse. Imagine, for example, that if we need to change the direction of FN several times, we don’t need to pass fn each time, just the object we want to bind. Here are a few more typical examples of parameter reuse using Coriolization functions.

  • Regular judgment

As follows, a function that encapsulates a regex judgment, passing in a regular expression and a target string, returns the result. No problem.

function check(targetString, reg) {
    return reg.test(targetString);
}

check(/^1[34578]\d{9}$/, '14900000088');
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]');
Copy the code

When the business requirement is just to determine the phone number or email address, it is inefficient to pass in the corresponding re each time, so it can be encapsulated again using the Currization function.

function curring(reg) {
  return (str) => {
    return reg.test(str);
  };
}
var checkPhone = curring(/^1[34578]\d{9}$/);
var checkEmail = curring(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);

console.log(checkPhone("183888888")); // false
console.log(checkPhone("17654239819")); // true
console.log(checkEmail("[email protected]")); // true
Copy the code
  • Judge HTML tags

We know that custom components in Vue can be written as HTML tags in templates. So when Vue encounters a tag, how does it know if it’s an HTML tag or a custom component? The general idea is that there are only a few dozen types of HTML tags. Store it in an array and check if it’s in the array every time you encounter it. However, there are obvious disadvantages to this approach, as you loop through the array every time, which can be very performance consuming. We can turn an array structure into a dictionary.

let set = {}; 
tags.forEach( key => set[ key ] = true )
Copy the code

To further optimize, pass in the tag collection as a parameter. This encapsulates a generic function that can determine whether an element is in a specified collection.

let tags = "div,p,a,img,ul,li".split(","); function makeMap(keys) { let set = {}; tags.forEach((key) => (set[key] = true)); return function (tagName) { return !! set[tagName.toLowerCase()]; }; } let isHTMLTag = makeMap(tags); console.log(isHTMLTag('Menu')) // false console.log(isHTMLTag('div')) // trueCopy the code
  • Custom encapsulating bind methods

Bind, in contrast to call and apply, permanently changes the this reference, reusing the target object passed in with call/apply, and can therefore be wrapped with a Currified function.

function foo(action) { console.log(this.name + action); } const obj1 = {name: "int ",}; foo.__proto__.myBind = function (obj) { const fun = this; return function (args) { fun.call(obj, args); }; }; const newFoo = foo.myBind(obj1); NewFoo (" run "); Xiao Ming runsCopy the code

There are many more advantages to the Currization function. We should focus on understanding the design idea and application scenarios of Coriolization function. In the real business of some fixed operations, need to reuse data, or to extend the functionality of the function, you can consider using the currization function. More advantages of Currization need to be realized in actual coding.

Refer to the link: www.jianshu.com/p/5e1899fe7…