Le mot «pit» signifie «piège». En raison de la nature du "langage faible" de JavaScript, il est extrêmement lâche et flexible pendant l'utilisation, mais il est également extrêmement facile de "être frappé". Ces fosses sont souvent cachées, vous devez donc garder les yeux ouverts pour faire de la navigation lisse sur la route de l'apprentissage et de l'application de JS.
1. Variables globales
JavaScript gère les étendues via des fonctions. Les variables déclarées à l'intérieur d'une fonction ne sont que dans cette fonction et ne sont pas disponibles en dehors de la fonction. D'un autre côté, les variables globales sont déclarées en dehors de toute fonction ou sont utilisées simplement et simplement sans déclaration.
"Utilisez-le simplement sans déclarer" signifie que les variables sont déclarées sans utiliser le mot-clé VAR. Nous avons déjà précisé que la façon d'éviter la génération implicite de variables globales est de déclarer autant que possible les variables avec le mot clé VAR.
Mais pensez-vous qu'il est normal d'utiliser VAR? Jetons un coup d'œil à cette fosse:
La copie de code est la suivante:
fonction foo () {
var a = b = 0;
// corps...
}
Peut-être que ce que vous attendez, ce sont deux variables locales, mais B est une véritable variable globale. Pourquoi? Parce que l'opération d'affectation est de droite à gauche, cela équivaut donc à:
La copie de code est la suivante:
fonction foo () {
var a = (b = 0);
// corps...
}
D. B est donc une variable globale.
Remplissez la fosse: déclarations variables, il est préférable de venir un par un, ne faites pas en gros ~ _ ~;
2. Déclaration variable
Jetons un coup d'œil à la fosse en premier:
La copie de code est la suivante:
myname = "global";
fonction foo () {
alerte (myname);
var myname = "local";
alerte (myname);
}
foo ();
À première vue, nous nous attendons à ce que les résultats de deux alertes soient "mondiaux" et "locaux", respectivement, mais les résultats réels sont "non définis" et "locaux". Pourquoi? Parce que les variables sont déclarées dans la même portée (même fonction) et sont d'abord analysées par le haut de la portée.
Ainsi, le comportement d'exécution de l'extrait de code ci-dessus peut ressembler à ceci:
La copie de code est la suivante:
fonction foo () {
var myname;
alerte (myname); // non défini "
myname = "local";
alerte (myname); // "locale"
}
Utilisez une autre fosse pour tester si vous comprenez vraiment le pré-parsement:
La copie de code est la suivante:
if (! ("a" dans la fenêtre)) {
var a = 1;
}
alerte (a);
La déclaration d'une variable est avancée en haut du code et n'a pas encore été attribuée. Ensuite, entrez dans la déclaration IF et jugez que la fenêtre "A" est établie (A a été déclaré comme une variable globale), donc le résultat du calcul de la déclaration de jugement est faux, et l'instruction IF qui sautra, de sorte que la valeur de A n'est pas définie.
La copie de code est la suivante:
var a; // non défini "
console.log ("a" dans la fenêtre); // vrai
if (! ("a" dans la fenêtre)) {
var a = 1; // non exécuté
}
alerte (a); // non défini "
Remplissez la fosse: il est préférable de placer manuellement la déclaration variable en haut de la portée. Pour les variables qui ne peuvent pas être attribuées pour le moment, vous pouvez utiliser la méthode de déclaration d'abord puis d'attribution de valeurs.
3. Déclaration de fonction
Les déclarations de fonction sont également avancées vers le haut de la portée, et sont analysées et évaluées avant que toute expression et énoncé ne soit analysée et évaluée.
La copie de code est la suivante:
alerte (typeof foo); // "fonction"
fonction foo () {
// corps...
}
Vous pouvez le comparer:
La copie de code est la suivante:
alerte (typeof foo); // non défini "
var foo = function () {
// corps...
};
Si vous comprenez ce principe, allez-vous toujours tomber dans les pièges suivants?
La copie de code est la suivante:
fonction test () {
alerte ("1");
}
test();
fonction test () {
alerte ("2");
}
test();
Lors de l'exécution de l'extrait de code ci-dessus, les fenêtres contextuelles que vous voyez sont "2", pourquoi ne sont-elles pas "1" et "2" respectivement? C'est très simple, la déclaration de test est analysée avant le test (). Étant donné que ce dernier l'emporte sur le premier, le résultat des deux exécutions est "2".
Remplissez la fosse: dans la plupart des cas, j'utilise des expressions de fonction au lieu des déclarations de fonction, en particulier dans certains blocs d'instructions.
4. Expressions de fonction
Regardons d'abord l'expression de la fonction nommée. Bien sûr, il doit avoir un nom, par exemple:
Copiez le code comme suit: var bar = fonction foo () {
// corps...
};
Il convient de noter que le nom de la fonction n'est visible que sa fonction à l'intérieur. Comme les pièges suivants:
La copie de code est la suivante:
var bar = fonction foo () {
foo (); // fonctionne normalement
};
foo (); // Erreur: ReferenceError
Remplissez la fosse: essayez d'utiliser le plus grand possible des expressions de fonction (sauf à des fins de récursivité et de débogage), et n'utilisez jamais les noms de fonction à l'extérieur.
5. Fonction Auto-exécution
Pour les expressions de fonction, vous pouvez exécuter en ajoutant () par la suite, et les paramètres peuvent être passés entre parenthèses, tandis que la déclaration de fonction ne peut pas. fosse:
La copie de code est la suivante:
// (1) Ce n'est qu'un opérateur de regroupement, pas un appel de fonction!
// donc la fonction ici n'a pas été exécutée, c'est toujours une instruction
fonction foo (x) {
alerte (x);
} (1);
Les extraits de code suivants sont exécutés séparément et la fenêtre contextuelle affiche "1". Parce qu'avant (1), ce sont des expressions de fonction, donc le () n'est pas un opérateur de regroupement, mais un opérateur, indiquant l'exécution des appels.
Copiez le code comme suit: // Expression de fonction anonyme standard
var bar = fonction foo (x) {
alerte (x);
} (1);
// le précédent () convertit la déclaration de fonction en une expression
(fonction foo (x) {
alerte (x);
}) (1);
// L'ensemble () est une expression
(fonction foo (x) {
alerte (x);
} (1));
// nouvelle expression
nouvelle fonction foo (x) {
alerte (x);
} (1);
// &&, ||,!, +, -, ~ etc. Opérateurs (et virgules) pour désambiguïter les expressions de fonctions et les déclarations de fonction
// Ainsi, une fois que l'analyseur sait que l'un d'eux est une expression, les autres seront également par défaut aux expressions.
true && function foo (x) {
alerte (x);
} (1);
Remplissez la fosse: la clé de cette fosse est de comprendre l'essence de toutes sortes d'expressions de fonction.
6. Clôture dans la boucle
Ce qui suit démontre un piège commun:
La copie de code est la suivante:
<! doctype html>
<html lang = "en">
<adal>
<meta charset = "utf-8">
<Title> Document </Title>
</ head>
<body>
<h3> Lorsque vous cliquez sur les liens ci-dessous, affichez le nombre de sa séquence </h3>
<ul>
<li> <a href = "#"> lien # 0 </a> </li>
<li> <a href = "#"> lien # 1 </a> </li>
<li> <a href = "#"> lien # 2 </a> </li>
<li> <a href = "#"> lien # 3 </a> </li>
<li> <a href = "#"> lien # 4 </a> </li>
</ul>
</docy>
</html>
La copie de code est la suivante:
var links = document.getElementsByTAGName ("ul") [0] .getElementsByTagName ("A");
pour (var i = 0, l = links.length; i <l; i ++) {
liens [i] .onclick = fonction (e) {
E.PreventDefault ();
alert ("vous cliquez sur le lien #" + i);
}
}
Nous nous attendons à ce que lorsque vous cliquez sur le i-theron, nous obtenons la valeur de l'index I dans cette séquence. Cependant, quel que soit le lien cliqué, nous obtenons le résultat final de I après la boucle: "5".
Expliquez la raison: lorsque l'alerte est appelée, l'expression de la fonction anonyme dans la boucle FOR maintient une référence à la variable externe I (fermeture). À l'heure actuelle, la boucle s'est terminée et la valeur de i est modifiée à "5".
Remplissez la fosse: Afin d'obtenir le résultat souhaité, vous devez créer une copie de la variable I dans chaque boucle. Ce qui suit démontre la bonne approche:
La copie de code est la suivante:
<adal>
<meta charset = "utf-8">
<Title> Document </Title>
</ head>
<body>
<h3> Lorsque vous cliquez sur les liens ci-dessous, affichez le nombre de sa séquence </h3>
<ul>
<li> <a href = "#"> lien # 0 </a> </li>
<li> <a href = "#"> lien # 1 </a> </li>
<li> <a href = "#"> lien # 2 </a> </li>
<li> <a href = "#"> lien # 3 </a> </li>
<li> <a href = "#"> lien # 4 </a> </li>
</ul>
</docy>
</html>
La copie de code est la suivante:
var links = document.getElementsByTAGName ("ul") [0] .getElementsByTagName ("A");
pour (var i = 0, l = links.length; i <l; i ++) {
liens [i] .onclick = (fonction (index) {
Fonction de retour (e) {
E.PreventDefault ();
alert ("vous cliquez sur le lien #" + index);
}
})(je);
}
Comme vous pouvez le voir, la forme de (function () {...}) () est l'auto-exécution de la fonction mentionnée ci-dessus. I est transmis à l'index en tant que paramètre. Lorsque Alert s'exécute à nouveau, il a une référence à l'index. Pour le moment, cette valeur ne sera pas modifiée par la boucle. Bien sûr, après avoir compris le principe, vous pouvez également écrire comme ceci:
La copie de code est la suivante:
pour (var i = 0, l = links.length; i <l; i ++) {
(fonction (index) {
liens [i] .onclick = fonction (e) {
E.PreventDefault ();
alert ("vous cliquez sur le lien #" + index);
}
})(je);
}
Cela fonctionne aussi.