Maison > interface Web > js tutoriel > 10 bugs JavaScript courants et comment les corriger

10 bugs JavaScript courants et comment les corriger

小云云
Libérer: 2017-12-06 15:51:42
original
1456 Les gens l'ont consulté

La conception du langage JavaScript est trop flexible, il faut donc faire attention à l'utiliser et tomber dans les gouffres. La conception du langage JavaScript est trop flexible, et il faut faire attention à l'utiliser et tomber dans les gouffres. . Cet article partage avec vous 10 BUG JavaScript courants et comment les corriger. Aujourd’hui, près de 100 % des sites Web utilisent JavaScript. JavaScript semble être un langage très simple, mais ce n'est pas le cas. Il contient de nombreux détails sur lesquels il est facile de se tromper, ce qui peut entraîner des bugs si vous n'y prêtez pas attention.

1. Mauvaise référence à ce

Dans les fermetures ou les rappels, il est facile de se tromper sur la portée du mot-clé this. Par exemple :

Game.prototype.restart = function () {
  this.clearLocalStorage();
  this.timer = setTimeout(function() {
    this.clearBoard();    // 此处this指的是?
  }, 0);
};
Copier après la connexion

Si vous exécutez le code ci-dessus, nous verrons l'erreur :

Uncaught TypeError: undefined is not a function
Copier après la connexion

La raison de l'erreur est : lorsque vous appelez la fonction setTimeout, vous en fait L'appel est window.setTimeout(). La fonction anonyme passée dans setTimeout est dans l'environnement objet de window, donc this pointe vers window, mais window n'a pas de méthode clearBoard.

Comment le résoudre ? Définissez une nouvelle référence de variable pour pointer vers le Game de l'objet this, et vous pourrez ensuite l'utiliser.

Game.prototype.restart = function () {
  this.clearLocalStorage();
  var self = this;   // 将this指向的对象绑定到self
  this.timer = setTimeout(function(){
    self.clearBoard();
  }, 0);
};
Copier après la connexion

Ou utilisez la fonction bind() :

Game.prototype.restart = function () {
  this.clearLocalStorage();
  this.timer = setTimeout(this.reset.bind(this), 0);  // bind to 'this'
};

Game.prototype.reset = function(){
    this.clearBoard();    // 此处this的引用正确
};
Copier après la connexion

2. BUG lié à la portée du bloc

dans la plupart des langages de programmation Dans , chaque bloc fonction a un nouvelle portée indépendante, mais en JavaScript, ce n'est pas le cas. Par exemple :

for (var i = 0; i < 10; i++) {
  /* ... */
}
console.log(i);  // 会输出什么呢?
Copier après la connexion

Habituellement, dans ce cas, appeler console.log() affichera undefined ou signalera une erreur. Cependant, 10 sera affiché ici. En JavaScript, même si la boucle for est terminée, la variable i existe toujours et la dernière valeur est enregistrée. Certains développeurs l’oublient, ce qui entraîne de nombreux bugs. Nous pouvons utiliser let au lieu de for pour éviter ce problème.

3. Fuites de mémoire

Vous devez surveiller l'utilisation de la mémoire car les fuites sont difficiles à éviter. Des fuites de mémoire peuvent survenir en raison de références à des objets inexistants ou de références circulaires.

  • Comment éviter : Concentrez-vous sur l'accessibilité de l'objet.

  • Objets accessibles :

    • Objets accessibles depuis n'importe où dans la pile d'appels existante

    • Objet global

Lorsqu'un objet est accessible via une référence, il sera enregistré en mémoire. Le garbage collector du navigateur récupérera uniquement les objets inaccessibles.

4. Jugement d'égalité confus

JavaScript convertit automatiquement tous les types de variables dans les environnements booléens en types booléens, mais cela peut entraîner des bugs. Exemple :

// 所有都是true
console.log(false == &#39;0&#39;);
console.log(null == undefined);
console.log(" \t\r\n" == 0);
console.log(&#39;&#39; == 0);

// 注意:下面两个也是
if ({}) // …
if ([]) // …
Copier après la connexion

{} et [] sont tous deux des objets, et ils seront convertis en vrai. Afin d'éviter les bugs, il est recommandé d'utiliser === et !== à des fins de comparaison, car la conversion de type ne sera pas effectuée implicitement.

5. Opérations DOM inefficaces

En JavaScript, vous pouvez facilement utiliser le DOM (ajouter, modifier et supprimer), mais les développeurs le font souvent de manière très inefficace. Cela peut entraîner des bugs car ces opérations sont très gourmandes en calcul. Pour résoudre ce problème, il est recommandé d'utiliser Document Fragment si vous devez exploiter plusieurs éléments DOM.

Publicité : Il n'y a vraiment aucun bug dans votre code en ligne ? Bienvenue à utiliser Fundebug gratuitement ! Nous pouvons vous aider à trouver les BUG dès que possible

6. Mauvaise définition de la fonction dans la boucle for

Exemple :

var elements = document.getElementsByTagName(&#39;input&#39;);
var n = elements.length;    // 假设我们有10个元素
for (var i = 0; i < n; i++) {
    elements[i].onclick = function() {
        console.log("元素编号#" + i);
    };
}
Copier après la connexion

Si nous avons 10 éléments, alors cliquer sur n'importe quel élément affichera « Élément numéro #10 » ! Parce que lorsque onclick est appelé, la boucle for est terminée, donc tous les i valent 10.

Solution :

var elements = document.getElementsByTagName(&#39;input&#39;);
var n = elements.length;    // 假设有10个元素
var makeHandler = function(num) {  // outer function
     return function() {   // inner function
         console.log("元素编号##" + num);
     };
};
for (var i = 0; i < n; i++) {
    elements[i].onclick = makeHandler(i+1);
}
Copier après la connexion

makeHandler est appelé immédiatement lorsque la boucle for est exécutée, obtient la valeur actuelle i+1 et la stocke dans la variable num. makeHandlerRenvoie une fonction utilisant la variable num liée à l'événement click de l'élément.

7. Mauvais héritage via les prototypes

Si les développeurs ne comprennent pas correctement les principes de l'héritage, ils peuvent écrire du code bogué :

BaseObject = function(name) {
    if(typeof name !== "undefined") {
        this.name = name;
    } else {
        this.name = &#39;default&#39;
    }
};
var firstObj = new BaseObject();
var secondObj = new BaseObject(&#39;unique&#39;);

console.log(firstObj.name);  // -> 输出'default'
console.log(secondObj.name); // -> 输出'unique'
Copier après la connexion

Mais, si nous faisons le suivant :

delete secondObj.name;
Copier après la connexion

Ensuite :

console.log(secondObj.name); // -> 输出'undefined'
Copier après la connexion

Et ce que nous voulons en fait, c'est imprimer le nom par défaut.

BaseObject = function (name) {
    if(typeof name !== "undefined") {
        this.name = name;
    }
};

BaseObject.prototype.name = 'default';
Copier après la connexion

Chaque BaseObject hérite de l'attribut name et la valeur par défaut est default. À ce stade, si l'attribut secondObj de name est supprimé, la recherche dans la chaîne de prototypes renverra la valeur par défaut correcte.

var thirdObj = new BaseObject('unique');
console.log(thirdObj.name);  // -> 输出'unique'

delete thirdObj.name;
console.log(thirdObj.name);  // -> 输出'default'
Copier après la connexion

8. Références invalides dans les méthodes d'instance

Implémentons un constructeur simple pour créer des objets :

var MyObject = function() {}

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

var obj = new MyObject();
Copier après la connexion

Pour faciliter l'utilisation, nous définissons la variable whoAmI pour référencer obj.whoAmI :

var whoAmI = obj.whoAmI;
Copier après la connexion

Imprimez-le :

console.log(whoAmI);
Copier après la connexion

La console affichera :

function () {
    console.log(this === window ? "window" : "MyObj");
}
Copier après la connexion

Maintenant, comparons la différence entre les deux appels :

obj.whoAmI();  // 输出"MyObj" (和期望一致)
whoAmI();      // 输出"window" (竟然输出了window)
Copier après la connexion

当我们把obj.whoAmI赋值给whoAmI的时候,这个新的变量whoAmI是定义在全局下,因此this指向全局的window,而不是MyObj。如果我们真的要获取对MyObj的函数的引用,需要在其作用域下。

var MyObject = function() {}

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

var obj = new MyObject();
obj.w = obj.whoAmI;   // 任然在obj的作用域

obj.whoAmI();  // 输出"MyObj"
obj.w();       // 输出"MyObj"
Copier après la connexion

9. setTimeout/setInterval函数第一个参数误用字符串

如果你将一个字符串作为setTimeout/setTimeInterval,它会被传给函数构造函数并构建一个新的函数。该操作流程很慢而且低效,并导致bug出现。

var hello = function(){
  console.log("hello, fundebug !");
}
setTimeout("hello", 1000);
Copier après la connexion

一个好的替代方法就是传入函数作为参数:

setInterval(logTime, 1000);   // 将logTime函数传入

setTimeout(function() {       // 传入一个匿名函数
    logMessage(msgValue);     
  }, 1000);
Copier après la connexion

10. 未能成功使用strict mode

使用strict model会增加很多限制条件来加强安全和防止某些错误的出现,如果不使用strict mode,你就相当于少了一个得力的助手帮你避免错误:

  • 更加容易debug

  • 避免不小心定义了不该定义的全局变量

  • 避免this隐式转换

  • 避免属性名字或则参数值的重复使用

  • eval()更加安全

  • 无效地使用delete会自动抛出错误

以上内容就是10个JavaScript常见BUG及修复方法,希望能帮助到大家。

相关推荐:

PHP中调试函数debug_backtrace的使用方法介绍

JavaScript调试必备的5个debug技巧分享

JS中offsetWidth的bug及处理方法

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal