Home  >  Article  >  Web Front-end  >  Ten common mistakes in JavaScript, how many have you made?

Ten common mistakes in JavaScript, how many have you made?

黄舟
黄舟Original
2017-02-24 13:48:261287browse


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, interaction, etc.

If you are dealing with it for the first time, many people will think that js is very simple. Indeed, for many experienced engineers, or even beginners, there is almost no obstacle to implementing basic js functions. But the real functions of JS are more diverse and complex than many people imagine. Many detailed regulations of JavaScript will cause many unexpected bugs to appear on your web pages. Understanding these bugs is very important to becoming an experienced JS developer.

## Common mistake one: incorrect citation of this keyword

I once heard a comedian say:

"I have never been here, because I don't know where this is, is it somewhere other than there?"

This sentence more or less metaphors the development of js Developers have misunderstandings about the use of this keyword. What does This refer to? Does it have the same meaning as this in daily spoken English?

As js programming continues to become more complex and functional in recent years, the number of internal guidelines and references to a program structure has gradually increased.

Let’s look at this paragraph together. Code:

Game.prototype.restart = function () {   this.clearLocalStorage(); 

    this.timer = setTimeout(function(){     this.clearBoard();        }, 0);

 };

Running the above code will result in the following error:

Uncaught TypeError: undefined is not a function

Why is this? The call to this is closely related to the environment in which it is located. The reason why the above error occurs is because when you call the setTimeout() function, you are actually calling window.setTimeout(). Therefore, the function defined in setTimeout() is actually defined in the window context. There is no clearBoard() function method in window.

Two solutions are provided below. The first relatively simple and direct method is to store this in a variable so that it can be inherited in different environmental backgrounds:

Game.prototype.restart = function () {   this.clearLocalStorage();  

    var self = this;

    this.timer = setTimeout(function(){     self.clearBoard();}, 0); };

The second method is to use bind() method, but this is more complicated than the previous one. For students who are not familiar with bind(), you can check its usage on Microsoft official website: http://www.php.cn/

Game.prototype.restart = function () {   this.clearLocalStorage();  

    this.timer = setTimeout(this.reset.bind(this), 0); };      

Game.prototype.reset = function(){     this.clearBoard();};

above In the example, both this refers to Game.prototype.

Common Mistake 2: Misunderstanding of the Life Cycle of Traditional Programming Languages

Another common mistake is to think that there is a life cycle in JS with the thinking of other programming languages. Say this. Please look at the following code:

for (var i = 0; i < 10; i++) {   /* ... */ } console.log(i);

If you think that an undefined error will definitely be reported when running console.log(), then you are totally wrong. I'll tell you actually it returns 10.

Of course, in many other languages, when encountering such code, an error will definitely be reported. Because i has obviously exceeded its life cycle. The life of the variable defined in for ends after the loop ends. But in js, the life of i will continue. This phenomenon is called variable hoisting.

If we want to implement variables with a life cycle in a specific logical module like other languages, we can use the let keyword.

Common Mistake Three: Memory Leak

Memory leak is almost an unavoidable problem in js programming. If you are not particularly careful, various memory leaks will definitely occur during the final inspection process. Let’s give an example below:

var theThing = null; 

var replaceThing = function () {   

        var priorThing = theThing; 

        var unused = function () { 

                  if (priorThing) {       console.log("hi");     }   

       }; 

       theThing = {     longStr: new Array(1000000).join(&#39;*&#39;),  // 

                  someMethod: function () {       console.log(someMessage);     }   
       }; 
};   
setInterval(replaceThing, 1000);

If you run the above code, you will find that you have caused a large number of memory leaks, leaking 1M of memory per second. Obviously relying on GC (garbage collector) alone is Can't help you anymore. Judging from the above code, it seems that longstr is not recycled every time replaceThing is called. Why is this?

Each theThing structure contains a list of longstr structures. Every second when we call replaceThing, it will pass the current pointer to priorityThing. But here we will also see that there is no problem, because priorityThing first unblocks the pointer of the last function every time before accepting the new one. Assignment. And all of this happens in the replaceThing function body. According to common sense, when the function body ends, the local variables in the function will also be recycled by GC, so there will be no memory leak problem, but why? What happened to the above error?

This is because longstr is defined in a closure, and it is referenced by other closures. JS stipulates that when a variable external to the closure is introduced in the closure, when the closure This object cannot be garbage collected (GC) at the end. Regarding the memory leak problem in JS, you can check http://www.php.cn/

Common Mistake 4: Comparison Operator

One of the more convenient places in JavaScript is this Each result variable in a comparison operation can be forcibly converted to a Boolean type. But from another perspective, sometimes it also brings us a lot of inconvenience. The following examples are some code examples that have been bothering many programmers:

console.log(false == &#39;0&#39;); 

console.log(null == undefined); 

console.log(" \t\r\n" == 0); 

console.log(&#39;&#39; == 0);  // And these do too! 

if ({}) // ... 

if ([]) // ...

  最后两行的代码虽然条件判断为空(经常会被人误认为转化为false),但是其实不管是{ }还是[ ]都是一个实体类,而任何的类其实都会转化为true。就像这些例子所展示的那样,其实有些类型强制转化非常模糊。因此很多时候我们更愿意用 === 和 !== 来替代== 和 !=, 以此来避免发生强制类型转化。. ===和!== 的用法和之前的== 和 != 一样,只不过他们不会发生类型强制转换。另外需要注意的一点是,当任何值与 NaN 比较的时候,甚至包括他自己,结果都是false。因此我们不能用简单的比较字符来决定一个值是否为 NaN 。我们可以用内置的 isNaN() 函数来辨别:

console.log(NaN == NaN);    // false 

console.log(NaN === NaN);   // false 

console.log(isNaN(NaN));    // true

  常见错误五:低效的DOM操作

  js中的DOM基本操作非常简单,但是如何能有效地进行这些操作一直是一个难题。这其中最典型的问题便是批量增加DOM元素。增加一个DOM元素是一步花费很大的操作。而批量增加对系统的花销更是不菲。一个比较好的批量增加的办法便是使用 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));

  直接添加DOM元素是一个非常昂贵的操作。但是如果是先把要添加的元素全部创建出来,再把它们全部添加上去就会高效很多。

  常见错误6:在for循环中的不正确函数调用

  请大家看以下代码:

var elements = document.getElementsByTagName(&#39;input&#39;);

var n = elements.length; 

for (var i = 0; i < n; i++) {     

elements[i].onclick = function() {         

console.log("This is element #" + i);     }; }

  运行以上代码,如果页面上有10个按钮的话,点击每一个按钮都会弹出 “This is element #10”! 。这和我们原先预期的并不一样。这是因为当点击事件被触发的时候,for循环早已执行完毕,i的值也已经从0变成了。

  我们可以通过下面这段代码来实现真正正确的效果:

var elements = document.getElementsByTagName(&#39;input&#39;); 

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); }

  在这个版本的代码中, makeHandler 在每回循环的时候都会被立即执行,把i+1传递给变量num。外面的函数返回里面的函数,而点击事件函数便被设置为里面的函数。这样每个触发函数就都能够是用正确的i值了。

  常见错误7:原型继承问题

  很大一部分的js开发者都不能完全掌握原型的继承问题。下面具一个例子来说明:

BaseObject = function(name) {     

if(typeof name !== "undefined") 

{         this.name = name;     } 

else 

{         this.name = &#39;default&#39;     } };

  这段代码看起来很简单。如果你有name值,则使用它。如果没有,则使用 ‘default’:

var firstObj = new BaseObject(); 

var secondObj = new BaseObject(&#39;unique&#39;);  

console.log(firstObj.name);  // -> 结果是&#39;default&#39; 

console.log(secondObj.name); // -> 结果是 &#39;unique&#39;

  但是如果我们执行delete语句呢:

delete secondObj.name;

  我们会得到:

console.log(secondObj.name); // -> 结果是 &#39;undefined&#39;

  但是如果能够重新回到 ‘default’状态不是更好么? 其实要想达到这样的效果很简单,如果我们能够使用原型继承的话:

BaseObject = function (name) 

{     if(typeof name !== "undefined") 

{         this.name = name;     } };  

BaseObject.prototype.name = &#39;default&#39;;

  在这个版本中, BaseObject 继承了原型中的name 属性, 被设置为了 'default'.。这时,如果构造函数被调用时没有参数,则会自动设置为 default。相同地,如果name 属性被从BaseObject移出,系统将会自动寻找原型链,并且获得 'default'值:

 var thirdObj = new BaseObject(&#39;unique&#39;); 

 console.log(thirdObj.name);  

 delete thirdObj.name;

 console.log(thirdObj.name);  // -> 结果是 &#39;default&#39;

  常见错误8:为实例方法创建错误的指引

  我们来看下面一段代码:

var MyObject = function() {} 

 MyObject.prototype.whoAmI = function() {     

console.log(this === window ? "window" : "MyObj"); }; 

 var obj = new MyObject();

  现在为了方便起见,我们新建一个变量来指引 whoAmI 方法, 因此我们可以直接用 whoAmI() 而不是更长的obj.whoAmI():

var whoAmI = obj.whoAmI;

  接下来为了确保一切都如我们所预测的进行,我们可以将 whoAmI 打印出来:

console.log(whoAmI);

  结果是:

function () {     console.log(this === window ? "window" : "MyObj"); }

  没有错误!

  但是现在我们来查看一下两种引用的方法:

obj.whoAmI();  // 输出 "MyObj" (as expected) 

whoAmI();      // 输出 "window" (uh-oh!)

  哪里出错了呢?

  原理其实和上面的第二个常见错误一样,当我们执行 var whoAmI = obj.whoAmI;的时候,新的变量 whoAmI 是在全局环境下定义的。因此它的this 是指window, 而不是obj!

  正确的编码方式应该是:

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();  // 输出 "MyObj" (as expected) 

obj.w();       // 输出 "MyObj" (as expected)

  常见错误9:用字符串作为setTimeout 或者 setInterval的第一个参数

  首先我们要声明,用字符串作为这两个函数的第一个参数并没有什么语法上的错误。但是其实这是一个非常低效的做法。因为从系统的角度来说,当你用字符串的时候,它会被传进构造函数,并且重新调用另一个函数。这样会拖慢程序的进度。

setInterval("logTime()", 1000); 

setTimeout("logMessage(&#39;" + msgValue + "&#39;)", 1000);

  另一种方法是直接将函数作为参数传递进去:

setInterval(logTime, 1000);   

setTimeout(function() { 

logMessage(msgValue); }, 1000);

  常见错误10:忽略 “strict mode”的作用

   “strict mode” 是一种更加严格的代码检查机制,并且会让你的代码更加安全。当然,不选择这个模式并不意味着是一个错误,但是使用这个模式可以确保你的代码更加准确无误。

  下面我们总结几条“strict mode”的优势:

 1. Make debugging easier: Many errors will be ignored in normal mode. The "strict mode" mode will make debugging more rigorous.

 2. Prevent default global variables: In normal mode, naming a declared variable will automatically set the variable to a global variable. In strict mode, we cancel this default mechanism.

 3. Cancel the default conversion of this: In normal mode, directing the this keyword to null or undefined will automatically convert it to global. In strict mode, we cancel this default mechanism.

 4. Prevent duplicate variable declarations and parameter declarations: Duplicate variable declarations in strict mode will be thrown into error, 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 will also report an error, such as (e.g., function foo(val1, val2, val1){}),

 5. Make the eval() function more Safety.

 6. When encountering an invalid delete instruction, an error will be reported afterwards: the delete instruction cannot be executed on attributes that do not exist in the class. Under normal circumstances, this situation is just ignored silently, but in strict mode it will Reported an error.

Conclusion

Just like other technical languages, the more you understand JavaScript, how it works and why it works, the more you will master and use it skillfully. language. On the contrary, if you lack knowledge of JS patterns, you will encounter a lot of problems. Understanding some detailed syntax or functions of JS will help you improve your programming efficiency and reduce the problems you encounter during programming.

The above are ten common mistakes in JavaScript. How many have you made? For more related content, please pay attention to the PHP Chinese website (www.php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn