Today, JavaScript has become the core of web page editing. Especially in the past few years, the Internet has witnessed the emergence of a large number of JS libraries in SPA development, graphics processing, and interaction. If you deal with it for the first time, a lot...
Preface
Today, JavaScript has become the core of web page editing. Especially in the past few years, the Internet has witnessed the emergence of a large number of JS libraries in SPA development, graphics processing, and interaction.
If you deal with js for the first time, many people will think that js is very simple. Indeed, for many experienced engineers or even beginners, it is almost impossible to implement basic js functions. However, the real functions of JavaScript are more diverse and complex than many people think. Many detailed JavaScript regulations may cause many unexpected bugs on your webpage. Understanding these bugs is very important to become an experienced JS developer.
Common error 1: incorrect reference to this keyword
I once heard a comedian say:
"I have never been here, because I don't know where it is, except where it is ?"
This sentence is more or less a metaphor for the misunderstanding of this keyword used by developers in js development. What does This mean? Does it mean this in everyday oral english?
In recent years, JavaScript programming has become increasingly complicated and its functions have been diversified. internal guidance and references for a program structure have also gradually increased.
Let's take a look at this piece of code:
Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(function(){ this.clearBoard(); }, 0); };
The following error occurs when running the above Code:
Uncaught TypeError: undefined is not a function
Why? The call of this is closely related to its environment. The above error occurs because when you call the setTimeout () function, you actually call window. setTimeout (). therefore, the functions defined in setTimeout () are actually defined in the window background, and there is no clearBoard () function method in window.
Two solutions are provided below. The first simple and direct method is to store this in a variable so that it can be inherited in different environments:
Game.prototype.restart = function () { this.clearLocalStorage(); var self = this; this.timer = setTimeout(function(){ self.clearBoard();}, 0); };
The second method is to use the bind () method. However, this method is more complex than the previous one. If you are not familiar with bind (), you can check its usage on the Microsoft Official Website :#
Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(this.reset.bind(this), 0); }; Game.prototype.reset = function(){ this.clearBoard();};
In the above example, both of these refer to Game. prototype.
Common Error 2: Incorrect lifecycles in traditional programming languages
Another easy mistake is the thought of other programming languages. I think there is also a life cycle in JavaScript. See the following code:
for (var i = 0; i < 10; i++) { /* ... */ } console.log(i);
If you think that the undefined error is certainly returned when you run console. log (), you are wrong. I will tell you if it returns 10.
Of course, in many other languages, such code will certainly report an error. Because I has obviously exceeded its lifecycle. After a variable defined in for ends a loop, its life ends. However, in js, the I lifecycle will continue. This phenomenon is called variable hoisting.
If we want to implement variables with lifecycles in specific logic modules like other languages, we can use the let keyword.
Common error 3: Memory leakage
Memory leakage is almost unavoidable in js conversion. If you are not very careful, there will certainly be various memory leaks during the final check process. The following is an example:
var theThing = null; var replaceThing = function () { var priorThing = theThing; var unused = function () { if (priorThing) { console.log("hi"); } }; theThing = { longStr: new Array(1000000).join('*'), // someMethod: function () { console.log(someMessage); } }; }; setInterval(replaceThing, 1000);
If you run the above Code, you will find that you have caused a large amount of memory leakage, 1 MB of Memory leakage per second, it is clear that GC alone (Garbage Collector) can not help you. From the code above, it seems that longstr is not recycled every time the replaceThing is called. Why?
Each theThing structure contains a longstr structure list. Every second when we call replaceThing, it will pass the current point to priorThing. however, here we can see that there is no problem, because each time priorThing returns, it first unlinks the point of the previous function to accept the new value assignment. All of this happens in the replaceThing function body. Generally speaking, when the function body ends, the local variables in the function will be recycled by GC, there will be no memory leakage, but why is the above error?
This is because longstr is defined in a closure and referenced by other closures. js stipulates that when external variables of the closure are introduced in the closure, this object cannot be garbage collected (GC) when the closure ends ). For details about memory leakage in JS, refer #
Common error 4: Comparison Operators
A convenient part of JavaScript is that it can forcibly convert each result variable in comparison to a boolean type. But on the other hand, sometimes it will bring us a lot of inconvenience. The following examples are some code instances that have been plagued by many programmers:
console.log(false == '0'); console.log(null == undefined); console.log(" \t\r\n" == 0); console.log('' == 0); // And these do too! if ({}) // ... if ([]) // ...
Although the Code in the last two lines is null (often mistakenly converted to false), neither {} nor [] is actually an entity class, and any class will actually be converted to true. As shown in these examples, some types of forced conversion are actually very vague. Therefore, we are more willing to use = and! = To replace = and! = To avoid forced type conversion .. ===And! = Usage and previous = and! = Is the same, but they will not undergo type forced conversion. In addition, when comparing any value with NaN, or even itself, the result is false. Therefore, we cannot use simple comparison characters to determine whether a value is NaN. We can use the built-in isNaN () function to identify:
console.log(NaN == NaN); // false console.log(NaN === NaN); // false console.log(isNaN(NaN)); // true
Common error 5: inefficient DOM operations
The basic DOM operations in JavaScript are very simple, but how to perform these operations effectively remains a challenge. The most typical problem is to add DOM elements in batches. Adding a DOM element is a big step-by-step operation. However, increasing the number of instances in batches is more expensive for the system. A better method for batch addition is to use document fragments:
var p = document.getElementsByTagName("my_p"); var fragment = document.createDocumentFragment(); for (var e = 0; e < elems.length; e++) { fragment.appendChild(elems[e]); } p.appendChild(fragment.cloneNode(true));
Adding DOM elements directly is a very expensive operation. However, it would be much more efficient to create all the elements to be added first and then add them all.
Common Error 6: incorrect function call in the for Loop
Please refer to the following code:
var elements = document.getElementsByTagName('input');var n = elements.length; for (var i = 0; i < n; i++) { elements[i].onclick = function() { console.log("This is element #" + i); }; }
Run the above Code. If there are 10 buttons on the page, clicking each button will bring up "This is element #10 "! . This is not the same as we expected. This is because when the click event is triggered, the for loop has already been executed, and the I value has changed from 0.
We can use the following code to achieve true results:
var elements = document.getElementsByTagName('input'); var n = elements.length; var makeHandler = function(num) { // outer function return function() { console.log("This is element #" + num); }; }; for (var i = 0; i < n; i++) { elements[i].onclick = makeHandler(i+1); }
In the code of this version, makeHandler is executed immediately during every loop, and I + 1 is passed to the variable num. The function outside returns the function, and click the event function to set it to the function. In this way, each trigger function can use the correct I value.
Common error 7: Prototype inheritance
A large part of js developers cannot fully master the prototype inheritance issue. The following is an example:
BaseObject = function(name) { if(typeof name !== "undefined") { this.name = name; } else { this.name = 'default' } };
This code looks simple. If you have a name value, use it. If not, use 'default ':
Var firstObj = new BaseObject (); var secondObj = new BaseObject ('unique'); console. log (firstObj. name); //-> the result is 'default' console. log (secondObj. name); //-> the result is 'unique'
But what if we execute the delete statement:
delete secondObj.name;
We will get:
Console. log (secondObj. name); //-> the result is 'undefined'
But isn't it better to return to the 'default' status again? In fact, it is very easy to achieve this effect, if we can use prototype inheritance:
BaseObject = function (name) { if(typeof name !== "undefined") { this.name = name; } }; BaseObject.prototype.name = 'default';
In this version, BaseObject inherits the name attribute in the prototype and is set to 'default '.. At this time, if the constructor is called without parameters, it is automatically set to default. Similarly, if the name attribute is removed from the BaseObject, the system will automatically search for the prototype chain and obtain the 'default' value:
Var thirdObj = new BaseObject ('unique'); console. log (thirdObj. name); delete thirdObj. name; console. log (thirdObj. name); //-> the result is 'default'
Common error 8: Guide to instance method creation errors
Let's look at the following code:
var MyObject = function() {} MyObject.prototype.whoAmI = function() { console.log(this === window ? "window" : "MyObj"); }; var obj = new MyObject();
Now, for convenience, we create a variable to guide the whoAmI method, so we can directly use whoAmI () instead of longer obj. whoAmI ():
var whoAmI = obj.whoAmI;
Next we can print out whoAmI to make sure everything is as predicted:
console.log(whoAmI);
The result is:
function () { console.log(this === window ? "window" : "MyObj"); }
No error!
But now let's look at two reference methods:
Obj. whoAmI (); // output "MyObj" (as expected) whoAmI (); // output "window" (uh-oh !)
What went wrong?
The principle is actually the same as the second common error above. When we execute var whoAmI = obj. whoAmI;, the new variable whoAmI is defined in the global environment. Therefore, this indicates window, not obj!
The correct encoding method should be:
Var MyObject = function () {} MyObject. prototype. whoAmI = function () {console. log (this = window? "Window": "MyObj") ;}; var obj = new MyObject (); obj. w = obj. whoAmI; // still in the obj namespace obj. whoAmI (); // output "MyObj" (as expected) obj. w (); // output "MyObj" (as expected)
Common error 9: Use a string as the first parameter of setTimeout or setInterval.
First, we need to declare that there is no syntax error when using strings as the first parameter of the two functions. However, this is a very inefficient practice. From a system perspective, when you use a string, it will be passed into the constructor and re-call another function. This will slow down the progress of the program.
setInterval("logTime()", 1000); setTimeout("logMessage('" + msgValue + "')", 1000);
Another method is to directly pass the function as a parameter:
setInterval(logTime, 1000); setTimeout(function() { logMessage(msgValue); }, 1000);
Common error 10: Ignore "strict mode"
"Strict mode" is a more rigorous code check mechanism, and it will make your code more secure. Of course, not selecting this mode does not mean it is an error, but using this mode ensures that your code is more accurate.
Below we will summarize several advantages of "strict mode:
1. Make debugging easier: many errors will be ignored in normal mode, and the "strict mode" mode will make debugging more rigorous.
2. prevent default global variables: In normal mode, if you name a declared variable, the variable is automatically set to a global variable. In strict mode, the default mechanism is canceled.
3. Cancel the default conversion of this: In normal mode, if you direct this keyword to null or undefined, it will be automatically converted to global. In strict mode, the default mechanism is canceled.
4. prevent repeated variable declarations and parameter declarations: Repeated variable declarations in strict mode will be held wrong, such as (e.g ., var object = {foo: "bar", foo: "baz"};) at the same time, repeated use of the same parameter name in the function declaration also reports an error, such as (e.g ., function foo (val1, val2, val1 ){}),
5. Make eval () functions more secure.
6. when an invalid delete command is run, an error is reported: The delete command cannot be executed on the attributes not in the class. Normally, this is ignored silently, but an error is reported in strict mode.
Conclusion
Just like other technical languages, the deeper you know about JavaScript, how it works, and why it works, the more skillful you can master and use it. On the contrary, if you lack the knowledge of the JS model, you will encounter many problems. Understanding the syntax or functions in some details of JS will help you improve programming efficiency and reduce the problems encountered.
The above are the small mistakes that are easy to make in ten JavaScript. How many shots have you taken? For more information, see the PHP Chinese website (www.php1.cn )!