There are various pit and pit filling methods in JavaScript coding

  • 2020-03-30 03:13:43
  • OfStack

The word "pit" here means "trap". Due to the "weak language" nature of JavaScript, it is unusually loose and flexible in the use process, but it is also extremely easy to "fall into the trap". These pits are often hidden, so you must polish your eyes, in order to learn and apply JS on the road to go smoothly.

1. Global variables

JavaScript USES functions to manage scope. Variables declared inside a function are only inside the function, not outside the function. Global variables, on the other hand, are declared outside of any function or are simply used without being declared.

"Undeclared simple to use" refers to declaring variables without the var keyword. The way to avoid creating implicit global variables is to declare variables using the var keyword whenever possible.

But you think var is ok? Take a look at this pit:


function foo() {
    var a = b = 0;
    // body...
}

You might expect two local variables, but b is a real global variable. According to? Because the assignment operation is from right to left, so this is equivalent to:

 
function foo() {
    var a = (b = 0);
    // body...
}

So b is a global variable.

Fill pit: variable declaration, it is best to come one by one, do not engage in wholesale ~_~;

Declaration of variables

First look at the pit:

 
myName = "global";

function foo() {
    alert(myName);
    var myName = "local";
    alert(myName);
}

foo();

At first glance, we expected the results of both alerts to be "global" and "local," but the real results were "undefined" and "local." According to? Because variables are in the same scope (the same function), the declarations are lifted to the top of the scope and resolved first.

So the above code snippet might execute like this:


function foo() {
    var myName;
    alert(myName); // "undefined"
    myName = "local";
    alert(myName); // "local"
}

Use another pit to test if you really understand the preparsing:
 
if (!("a" in window)) {
    var a = 1;
}

alert(a);

The declaration of the a variable is advanced to the top of the code without being assigned a value. I'm going to go into the if statement and say "a" in window is true (a has been declared as a global variable), so I'm going to say false, and I'm going to jump out of the if statement, so a is undefined.

var a; // "undefined"
console.log("a" in window); // true

if (!("a" in window)) {
    var a = 1; //Does not perform
}

alert(a); // "undefined"

Pit: variable declaration, preferably manually placed at the top of the scope, for variables that cannot be assigned at the moment, can be used after the first declaration of the method.

Function declaration

Function declarations are also advanced to the top of the scope and are parsed and evaluated before any expression or statement

 
alert(typeof foo); // "function"

function foo() {
    // body...
}

Here's a comparison:

alert(typeof foo); // "undefined"

var foo = function () {
    // body...
};

Understand this truth of you, whether still can tread the pit below?

 
function test() {
    alert("1");
}

test();

function test() {
    alert("2");
}

test();

When you run the above code snippet, the two pop-ups you see are both "2". Why not "1" and "2" respectively? Quite simply, the declaration of test is parsed before test(), and since the latter overrides the former, the result of both executions is "2".

Fill in the holes: most of the time, I use function expressions instead of function declarations, especially in statement blocks.

Four, the function expression

First look at the named function expression, of course, it has to have a name, for example:

var bar = function foo() {
    // body...
};

Note that the name of a function is only visible inside its function. Such as the following pit:
 
var bar = function foo() {
    foo(); //The normal operation
};

foo(); //  Error: ReferenceError

Pit: use named function expressions sparingly (except for some recursion and debug purposes) and never use function names externally.

Five, the function of the self-execution

For function expressions, you can self-execute by adding () after it, and you can pass arguments in parentheses, whereas function declarations cannot. Pit:

 
//(1) this is just a grouping operator, not a function call!
//So this function is not executed, it's still a declaration
function foo(x) {
  alert(x);
}(1);

The following code snippets are popover to show "1" respectively, because before (1), all are functional expressions, so the () non-group operator here is the operator to indicate the call execution.

//Standard anonymous function expression
var bar = function foo(x) {
  alert(x);
}(1);

//The previous () converts the function declaration to an expression
(function foo(x) {
  alert(x);
})(1);

//The entire () is an expression
(function foo(x) {
  alert(x);
}(1));

//New expressions
new function foo(x) {
  alert(x);
}(1);

//, &&, | |! The +, -, ~ operators (as well as commas) disambiguate function expressions and function declarations
//So once the parser knows that one of them is already an expression, the others are by default
true && function foo(x) {
  alert(x);
}(1);
The & # 8203;
Fill in the hole: the key to this hole is to get at the heart of the various functional expressions.

Closures in loops

Here is a common pit:


<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h3>when clicking links below, show the number of its sequence</h3>
    <ul>
        <li><a href="#">link #0</a></li>
        <li><a href="#">link #1</a></li>
        <li><a href="#">link #2</a></li>
        <li><a href="#">link #3</a></li>
        <li><a href="#">link #4</a></li>
    </ul>
</body>
</html>


var links = document.getElementsByTagName("ul")[0].getElementsByTagName("a");

for (var i = 0, l = links.length; i < l; i++) {
    links[i].onclick = function (e) {
        e.preventDefault();
        alert("You click link #" + i);
    }        
}

We expect to get the value of index I of this sequence when the ith link is clicked, but no matter which link is clicked, we will get the final result of I after the loop: "5".

To explain why: when alert is called, the anonymous function expression within the for loop retains a reference to the external variable I (closure), at which point the loop ends and the value of I is changed to "5".

To get the desired result, you need to create a copy of the variable I in each loop. Here's how:


<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h3>when clicking links below, show the number of its sequence</h3>
    <ul>
        <li><a href="#">link #0</a></li>
        <li><a href="#">link #1</a></li>
        <li><a href="#">link #2</a></li>
        <li><a href="#">link #3</a></li>
        <li><a href="#">link #4</a></li>
    </ul>
</body>
</html>


var links = document.getElementsByTagName( " ul " )[0].getElementsByTagName( " a " );
for (var i = 0, l = links.length; i < l; i++) {
    links[i].onclick = (function (index) {
        return function (e) {
            e.preventDefault();
            alert("You click link #" + index);
        }
    })(i);
}

As you can see, (function () {... })() is the self-execution of the function mentioned above. I is passed to index as an argument. When alert is executed again, it will have a reference to index. Of course, once you understand how it works, you can also write:


for (var i = 0, l = links.length; i < l; i++) {
    (function (index) {
        links[i].onclick = function (e) {
            e.preventDefault();
            alert("You click link #" + index);
        }
    })(i);
}

It works too.


Related articles: