By valentinogagliardi

Click “like” and then look, wechat search [Big Move the world] pay attention to this person without dACHang background, but with a positive attitude upward. In this paper, making github.com/qq449245884… Has been included, the article has been categorized, also organized a lot of my documentation, and tutorial materials.

Everyone said there was no project on your resume, so I found one and gave it away【 Construction tutorial 】.

The use of global variables is bug-prone, and we are often taught not to use global variables when possible, even though they can be useful in some cases. For example, when using JS in a browser, we can access the global Window object. There are many useful methods in Window, such as:

window.alert('Hello world'); // Shows an alert
window.setTimeout(callback, 3000); // Delay execution
window.fetch(someUrl); // make XHR requests
window.open(); // Opens a new tab
Copy the code

These methods are also used like this:

alert('Hello world'); // Shows an alert
setTimeout(callback, 3000); // Delay execution
fetch(someUrl); // make XHR requests
open(); // Opens a new tab
Copy the code

It’s convenient. Redux is another example of a “good” global variable: the state of the entire application is stored in a SINGLE JS object that can be accessed from the entire application (via Redux). But when you have 50 coders on a team, how do you deal with code like this:

var arr = []; function addToArr(element) { arr.push(element); return element + " added!" ; }Copy the code

What are the chances that our colleague will create a new global array named ARR in another file? I think it’s very high. Another reason globals in JS suck is that the engine is friendly enough to create them for us. If you forget to add var before the variable name, it looks like this:

name = "Valentino";
Copy the code

The JS engine creates a global variable, or worse, an “unexpected” variable can be created in a function:

function doStuff() {
  name = "Valentino";
}

doStuff();

console.log(name); // "Valentino"
Copy the code

Innocent functions end up polluting the global environment. Fortunately, this behavior can be eliminated with “strict mode”, and using “use strict” on every JS file is enough to avoid silly errors:

"use strict";

function doStuff() {
  name = "Valentino";
}

doStuff();

console.log(name); // ReferenceError: name is not defined
Copy the code

However, using strict patterns all the time is a problem, not every developer will use strict patterns, so we have to find a way to solve the problem of “global variable contamination”. Fortunately, JS has always had a built-in mechanism to solve this problem.

Reveal the closure

So, how do we protect global variables from contamination? Let’s start with a simple solution and move arr into a function:

function addToArr(element) {
  var arr = [];
  arr.push(element);
  return element + " added to " + arr;
}
Copy the code

Seems reasonable, but the result is not what we expected:

var firstPass = addToArr("a");
var secondPass = addToArr("b");
console.log(firstPass); // a added to a
console.log(secondPass); // b added to b
Copy the code

The arR is reset every time the function is called. It is now a local variable, whereas the arR we declared in the first example was a global variable. Global variables are “real time” and cannot be surrounded. Local variables are destroyed after the function is executed and there seems to be no way to prevent local variables from being destroyed, right? Will closures help? But what is a closure?

JS functions can contain other functions, which is quite common by now, as follows:

function addToArr(element) {
  var arr = [];

  function push() {
    arr.push(element);
  }

  return element + " added to " + arr;
}
Copy the code

But what if we just return push? As follows:

function addToArr(element) {
  var arr = [];

  return function push() {
    arr.push(element);
    console.log(arr);
  };

  //return element + " added to " + arr;
}
Copy the code

The outer function becomes a container that returns another function. The second return statement is commented out because the code is never executed. At this point, we know that the result of a function call can be stored in a variable.

var result = addToArr();
Copy the code

Now result becomes an executable JS function:

var result = addToArr();
result("a");
result("b");
Copy the code

Just fix it by moving the argument “element” from the outer function to the inner function:

function addToArr() {
  var arr = [];

  return function push(element) {
    arr.push(element);
    console.log(arr);
  };

  //return element + " added to " + arr;
}
Copy the code

Here’s the full code:

function addToArr() {
  var arr = [];

  return function push(element) {
    arr.push(element);
    console.log(arr);
  };

  //return element + " added to " + arr;
}

var result = addToArr();
result("a"); // [ 'a' ]
result("b"); // [ 'a', 'b' ]
Copy the code

This is called a JS closure: a function that remembers its environment variables. To do this, the inner function must be the return value of a enclosing (outer) function. This is also called the factory function. The code can be tweaked slightly, changes can be better named, and internal functions can be anonymous:

function addToArr() {
  var arr = [];

  return function(element) {
    arr.push(element);
    return element + " added to " + arr;
  };
}

var closure = addToArr();
console.log(closure("a")); // a added to a
console.log(closure("b")); // b added to a,b
Copy the code

It should now be clear that “closures” are internal functions. But the question remains: Why are we doing this? What is the real purpose of JS closures?

The need for closures

In addition to purely “academic” knowledge, JS closures have many uses:

  • Provide private global variables
  • Saving variables (state) between function calls

One of the most interesting applications of closures in JS is the module pattern. Prior to ES6, there was no other way to modularize JS code and provide private variables and methods other than wrapping variables and methods in functions. Closures combined with function expressions that are invoked immediately are by far the most common solution.

var Person = (function(){
  // do something
})()
Copy the code

There can be “private” variables and methods in modules:

var Person = (function() {
  var person = {
    name: "",
    age: 0
  };

  function setName(personName) {
    person.name = personName;
  }

  function setAge(personAge) {
    person.age = personAge;
  }
})();
Copy the code

We can’t access Person. name or person.age from the outside. We can’t call setName or setAge. All content within a module is “private.” If we want to expose our method, we can return an object containing a reference to the private method.

var Person = (function() { var person = { name: "", age: 0 }; function setName(personName) { person.name = personName; } function setAge(personAge) { person.age = personAge; } return { setName: setName, setAge: setAge }; }) ();Copy the code

If you want to get a Person object, add a method that gets it and return it.

var Person = (function() { var person = { name: "", age: 0 }; function setName(personName) { person.name = personName; } function setAge(personAge) { person.age = personAge; } function getPerson() { return person.name + " " + person.age; } return { setName: setName, setAge: setAge, getPerson: getPerson }; }) (); Person.setName("Tom"); Person.setAge(44); var person = Person.getPerson(); console.log(person); // Tom 44Copy the code

This way, the person object is not available externally:

console.log(Person.person); // undefined
Copy the code

The module pattern is not the only way to construct JS code. Using objects, we can achieve the same result:

var Person = {
  name: "",
  age: 0,
  setName: function(personName) {
    this.name = personName;
  }
  // other methods here
};
Copy the code

But then, internal attributes are no longer private:

var Person = {
  name: "",
  age: 0,
  setName: function(personName) {
    this.name = personName;
  }
  // other methods here
};

Person.setName("Tom");

console.log(Person.name); // Tom
Copy the code

This is one of the main selling points of the module. Another benefit is that modules help organize your code, making it reusable and readable. For example, a developer can see the following code and get a rough idea of what it does:

"use strict"; var Person = (function() { var person = { name: "", age: 0 }; function setName(personName) { person.name = personName; } function setAge(personAge) { person.age = personAge; } function getPerson() { return person.name + " " + person.age; } return { setName: setName, setAge: setAge, getPerson: getPerson }; }) ();Copy the code

conclusion

Global variables are bug-prone and should be avoided as much as possible. Sometimes global variables are useful and need to be used with great care, because the JS engine is free to create global variables.

Many patterns have emerged over the years to manage global variables, and the module pattern is one of them. Module patterns are built on closures, which are inherent in JS. A closure in JS is a function that “remembers” its variable environment, even between subsequent function calls. When we return a function from another function, we create a closure. This pattern is also called “factory function **”.

thinking

  • What is a closure?
  • What are the downsides of using global variables?
  • What is a JS module and why do you use it?

The bugs that may exist after code deployment cannot be known in real time. In order to solve these bugs, I spent a lot of time on log debugging. Incidentally, I recommend a good BUG monitoring tool for youFundebug.

Original text: github.com/valentinoga…

communication

This article is updated every week, you can search wechat “big move the world” for the first time to read and urge more (one or two earlier than the blog hey), this article GitHub github.com/qq449245884… It has been included and sorted out a lot of my documents. Welcome Star and perfect. You can refer to the examination points for review in the interview.