Je veux écrire une bibliothèque de classe JavaScript efficace mais je ne peux pas commencer;
Essayez de lire la bibliothèque des autres, mais comprenez-le comme s'il était compris;
Je prévois d'étudier bien les fonctions JS avancées, mais le contenu du livre faisant autorité est trop dispersé.
Même si vous vous souvenez de "l'utilisation", vous ne pensez pas à la "méthode" lorsque vous voulez "utiliser".
Peut-être que vous, comme moi, semblez avoir une force invisible qui retient nos plans, nous faisant penser à plusieurs reprises que les limites des connaissances nous ont rendus immobiles et difficiles à avancer.
Au cours de cette période, divers devoirs, conception de cours et rapports expérimentaux ont doublé. Il est rare de se faufiler un peu de temps, de ne jamais dormir et de trier les livres que j'ai lus dans le passé juste pour être plus près de l'écriture de ma propre bibliothèque.
Cet article est référencé à partir de "JavaScript Language Essence" et "JavaScript efficace". Tous les exemples ont été débogués. Après les avoir compris, je veux rendre certains principes «profonds» un peu plus simples.
1. Portée variable
La portée est comme l'oxygène aux programmeurs. C'est partout, et vous n'y pensez même pas. Mais lorsqu'il est pollué (comme l'utilisation d'objets globaux), vous vous sentirez étouffant (comme une réponse à l'application lente). Les règles de portée du noyau JavaScript sont simples, soigneusement conçues et très puissantes. Une utilisation efficace de JavaScript nécessite de maîtriser certains des concepts de base de la portée variable et de comprendre certaines situations extrêmes qui peuvent entraîner des problèmes insaisissables et ennuyeux.
1.1 Essayez d'utiliser le moins de variables globales le moins possible
JavaScript est facile à créer des variables dans un espace de noms global. La création de variables globales est sans effort car elle ne nécessite aucune forme de déclaration et peut être accessible automatiquement par tout le code de l'ensemble du programme.
Pour nous, les débutants, lors de la rencontre de certains besoins (par exemple, lorsque les données transmises sont enregistrées, en attendant un certain temps pour être appelé, ou lorsqu'une certaine fonction est souvent utilisée), nous pensons enfin aux fonctions globales. Même la pensée axée sur le processus de la langue C que j'ai apprise au cours de ma première année est trop profondément enracinée, et le système est parfaitement plein de fonctions. La définition des variables globales peut polluer les espaces de noms publics partagés et peut entraîner des conflits de dénomination inattendus. Les variables globales ne sont pas non plus propices à la modularité, car elle provoque un couplage inutile entre les composants indépendants du programme. Sérieusement parlant, trop mondial (y compris les feuilles de style, définissant directement les styles de div ou a) et les intégrer dans les développements de plusieurs personnes seront une erreur catastrophique. C'est pourquoi tout le code jQuery est enveloppé dans une expression anonyme instantanément exécutée - des fonctions anonymes auto-falsières. Lorsque le navigateur charge le fichier jQuery, il démarre l'exécution immédiatement après avoir appelé la fonction anonyme, initialisant divers modules de jQuery pour éviter de détruire et de polluer les variables globales et d'affecter d'autres codes.
La copie de code est la suivante:
(fonction (fenêtre, indéfinie) {
var jQuery = ...
// ...
window.jquery = fenêtre. $ = jQuery;
})(fenêtre);
En outre, vous pouvez penser qu'il est plus pratique de "écrire comment vous d'abord et de l'organiser plus tard", mais d'excellents programmeurs prêteront constamment attention à la structure du programme, classeront en continu des fonctions connexes et séparent des composants non pertinents, et ces comportements font partie de la formule de programmation.
Étant donné que les espaces de noms globaux sont le seul moyen pour les composants indépendants des programmes JavaScript à interagir, l'utilisation de contrôles de dénomination globale est inévitable. Les composants ou les bibliothèques doivent définir certaines variables globales. Pour une utilisation par d'autres parties du programme. Sinon, il est préférable d'utiliser des variables locales.
La copie de code est la suivante:
this.foo; // non défini
foo = "Global Foo";
this.foo; // "Global Foo"
var foo = "Global Foo";
this.foo = "changé";
foo; // changé
L'espace de noms global de JavaScript est également exposé à des objets globaux accessibles dans la portée globale du programme, qui sert de valeur initiale de ce mot-clé. Dans un navigateur Web, l'objet global est lié à la variable de fenêtre globale. Cela signifie qu'il existe deux façons de créer une variable globale: le déclarer avec VAR dans la portée globale, ou l'ajouter à l'objet global. L'avantage de l'utilisation de déclarations VAR est qu'ils peuvent clairement exprimer l'impact des variables globales dans la portée du programme.
Étant donné que les références aux variables globales liées peuvent entraîner des erreurs d'exécution, des étendues de sauvegarde claire et concise permettra aux utilisateurs de code de comprendre plus facilement les variables globales que le programme déclare.
Étant donné que l'objet global fournit un mécanisme de réponse dynamique pour l'environnement global, il peut être utilisé pour interroger un environnement en cours d'exécution et détecter les fonctionnalités disponibles sur cette plate-forme.
Eg.es5 introduit un objet JSON global pour lire et écrire des données de format JSON.
La copie de code est la suivante:
if (! this.json) {
this.json = {
Parse: ..,
Stringify: ...
}
}
Si vous fournissez une implémentation de JSON, vous pouvez bien sûr utiliser simplement et inconditionnellement votre propre implémentation. Mais les implémentations intégrées fournies par l'environnement hôte sont presque plus adaptées car elles sont écrites dans le navigateur en C. car elles vérifient strictement la précision et la cohérence en fonction de certaines normes et offrent généralement de meilleures performances que les implémentations tierces.
Le fonctionnement de base des chaînes de simulation de conception de cours de structure de données nécessitait que les méthodes fournies par le langage lui-même ne pouvaient pas être utilisées. JavaScript implémente très bien les opérations de base des tableaux. Si ce n'est que pour les besoins généraux d'apprentissage, l'idée des méthodes de simulation fournies par la langue elle-même est bonne, mais si vous investissez vraiment dans le développement, vous n'avez pas besoin d'envisager de choisir d'utiliser des méthodes intégrées JavaScript dès que possible.
1.2 Évitez d'utiliser avec
L'énoncé avec une «commodité» qui rend votre application peu fiable et inefficace. Nous devons appeler une série de méthodes sur un seul objet tour à tour. L'utilisation de l'instruction avec peut facilement éviter les références en double aux objets:
La copie de code est la suivante:
État de la fonction (info) {
var widget = new widget ();
avec (widget) {
Setbackground ("Blue");
Setforeground ("blanc");
setText ("Status:" + info);
montrer();
}
}
Il est également très tentant d'utiliser l'instruction avec "Importer" (Importer) les variables à partir d'un objet de module.
La copie de code est la suivante:
fonction f (x, y) {
avec (math) {
Retour Min (Round (X), SQRT (Y)); // Citation abstraite
}
}
En fait, JavaScript traite toutes les variables de la même manière. JavaScript commence à partir de la portée la plus intérieure et recherche des variables vers l'extérieur. Le langage avec le langage traite un objet comme s'il représentait une portée de variable, donc à l'intérieur du bloc de code avec le bloc, les recherches de variables commencent par rechercher des attributs du nom de variable donné. Si la propriété n'est pas trouvée dans cet objet, continuez à rechercher dans la portée externe. La référence à chaque variable externe dans le bloc avec le bloc suppose implicitement qu'il n'y a pas d'attribut avec le même nom dans l'objet avec l'objet (et l'un de ses objets prototypes). La création ou la modification d'un objet avec ou son prototype ailleurs dans le programme ne suit pas nécessairement ces hypothèses. Le moteur JavaScript ne lit certainement pas le code local pour obtenir les variables locales que vous utilisez. La portée JavaScript peut être représentée comme des structures de données internes efficaces et les recherches variables sont très rapides. Cependant, comme le bloc de code avec le code doit rechercher la chaîne prototype de l'objet pour trouver toutes les variables dans le code avec le code, sa vitesse d'exécution est beaucoup inférieure à celle du bloc de code général.
Au lieu de la langue avec le langage, il est simple de lier l'objet à un nom de variable court.
La copie de code est la suivante:
État de la fonction (info) {
var w = nouveau widget ();
w.setbackground ("bleu");
w.setForeground ("blanc");
w.seTText ("Status:" + info);
w.show ();
}
Dans d'autres cas, la meilleure façon est de lier explicitement les variables locales aux propriétés pertinentes.
La copie de code est la suivante:
fonction f (x, y) {
var min = math.min,
rond = math.round,
sqrt = math.sqrt;
return min (rond (x), sqrt (y));
}
1.3 compétent dans la fermeture
Il y a un seul concept pour comprendre les fermetures:
a) JavaScript vous permet de référencer les variables définies en dehors de la fonction actuelle.
La copie de code est la suivante:
Fonction Makeandwich () {
var magicingredient = "beurre d'arachide";
Fonction Make (remplissage) {
retour magicingEdient + "et" + remplissage;
}
Retour Make ("Jelly");
}
Makeandwich (); // "beurre d'arachide et gelée"
b) Même si la fonction externe est revenu, la fonction actuelle peut toujours se référer à la variable définie par la fonction externe.
La copie de code est la suivante:
Fonction Makeandwich () {
var magicingredient = "beurre d'arachide";
Fonction Make (remplissage) {
retour magicingEdient + "et" + remplissage;
}
retour à faire;
}
var f = sandwichmaker ();
f ("gelée"); // "beurre d'arachide et gelée"
f ("bananes"); // "beurre d'arachide et bananes"
f ("Mallows"); // "beurre d'arachide et salons"
Les valeurs de fonction de JavaScriptD contiennent plus d'informations que le code requis pour exécuter lorsqu'ils sont appelés. De plus, les valeurs de fonction JavaScript stockent également en interne les variables auxquelles ils peuvent se référer définis dans leur portée fermée. Les fonctions qui suivent les variables dans la portée qu'ils couvrent sont appelées fermetures.
La fonction de faire est une fermeture dont le code fait référence à deux variables externes: MagicingEdient et remplissage. Chaque fois que la fonction de faire est appelée, son code peut se référer à ces deux variables car la fermeture stocke ces deux variables.
Une fonction peut se référer à toute variable dans sa portée, y compris les variables de paramètre et de fonction externe. Nous pouvons utiliser ceci pour écrire des fonctions plus générales de sandwichmaker.
La copie de code est la suivante:
Fonction Makeandwich (MagicingEntiment) {
Fonction Make (remplissage) {
retour magicingEdient + "et" + remplissage;
}
retour à faire;
}
var f = sandwichmaker ("Ham");
f ("fromage"); // "Ham et fromage"
f ("moutarde"); // "Ham et moutarde"
Les fermetures sont l'une des caractéristiques les plus élégantes et les plus expressives du JavaScript et sont également au cœur de nombreux idiomes.
c) La fermeture peut mettre à jour la valeur d'une variable externe. En fait, les fermetures stockent des références à des variables externes, et non des copies de leurs valeurs. Par conséquent, toute fermeture avec accès à ces variables externes peut être mise à jour.
La copie de code est la suivante:
Box de fonction () {
var val = non défini;
retour {
set: function (newVal) {val = newVal;},
get: function () {return val;},
type: function () {return typeof val;}
};
}
var b = box ();
B.Type (); //indéfini
b.set (98.6);
b.get (); // 98.6
B.Type (); // numéro
Cet exemple produit un objet contenant trois fermetures. Ces trois fermetures sont des propriétés définies, types et obtiennent des propriétés, et elles partagent toutes l'accès aux variables VAL, et la fermeture de set met à jour la valeur de VAL. Ensuite, appelez Get et tapez pour afficher les résultats mis à jour.
1.4 Comprendre l'amélioration de la déclaration variable
JavaScript prend en charge cette portée de la méthode (les références à la variable FOO seront liées à la portée qui déclare la plus proche de la variable FOO), mais ne prend pas en charge la portée au niveau du bloc (la portée définie par la variable n'est pas l'instruction ou le bloc de code fermé le plus proche).
Ne pas comprendre cette fonctionnalité conduira à certains bogues subtils:
La copie de code est la suivante:
fonction iswinner (joueur, autres) {
var le plus élevé = 0;
pour (var i = 0, n = autres.length; i <n; i ++) {
var joueur = autres [i];
if (player.score> le plus haut) {
le plus élevé = le player.score;
}
}
return player.score> le plus élevé;
}
1.5 Méfiez-vous de la portée maladroite des expressions de fonction de dénomination
La copie de code est la suivante:
fonction double (x) {return x * 2; }
var f = fonction (x) {return x * 2; }
Le même code de fonction peut également être utilisé comme expression, mais a des significations complètement différentes. La différence officielle entre les fonctions anonymes et les expressions de fonction nommées est que ce dernier est lié à une variable avec le même nom de fonction que son nom de fonction, qui sert de variable locale de la fonction. Cela peut être utilisé pour écrire des expressions de fonction récursives.
La copie de code est la suivante:
var f = fonction find (arbre, key) {
// ...
return find (arbre.left, key) ||
trouver (arbre.Right, key);
}
Il convient de noter que la portée de la découverte variable n'est que dans sa propre fonction. Contrairement aux déclarations de fonction, les expressions de fonction nommées ne peuvent pas être référencées à l'extérieur via son nom de fonction interne.
La copie de code est la suivante:
trouver (mytree, "foo"); // error: find n'est pas défini;
var constructor = function () {return null; }
var f = fonction () {
Retour Constructor ();
};
f (); // {} (dans les environnements es3)
Le programme semble produira Null, mais il produira en fait un nouvel objet.
Étant donné que la variable de fonction nommée hérite object.prototype.constructor (c'est-à-dire le constructeur d'Oject), tout comme avec les instructions, cette portée sera affectée par les changements dynamiques de object.prototype. La façon d'éviter l'objet contaminant la portée des expressions de fonction dans le système est d'éviter d'ajouter des propriétés dans l'objet.Protype à tout moment pour éviter d'utiliser des variables locales avec le même nom que la propriété standard objet.prototype.
Un autre inconvénient dans le moteur JavaScript populaire est la promotion de la déclaration des expressions de fonction nommées.
La copie de code est la suivante:
var f = fonction g () {return 17;}
g (); // 17 (dans un environnement non conformat)
Certains environnements JavaScript utilisent même les deux fonctions F et G comme différents objets, entraînant une allocation de mémoire inutile.
1.6 Méfiez-vous de la portée maladroite pour les fonctions de bloc local
La copie de code est la suivante:
fonction f () {return "global"; }
Test de fonction (x) {
fonction f () {return "local";}
var result = [];
if (x) {
résultat.push (f ());
}
résultat.push (f ());
résultat résultat résultat;
}
test (true); // ["local", "local"]
test (false); //["locale"]
La copie de code est la suivante:
fonction f () {return "global"; }
Test de fonction (x) {
var result = [];
if (x) {
fonction f () {return "local";}
résultat.push (f ());
}
résultat.push (f ());
résultat résultat résultat;
}
test (true); // ["local", "local"]
test (false); //["locale"]
JavaScript n'a pas de portée au niveau du bloc, donc la portée de la fonction interne F devrait être la fonction de test entière. Certains environnements JavaScript le font, mais pas tous les environnements JavaScript. Les implémentations JavaScript rapportent des fonctions telles que des erreurs en mode strict (les programmes en mode strict avec les déclarations de fonctions de bloc local se rapporteront comme une erreur de syntaxe), ce qui aide à détecter le code non portable, donnant une sémantique plus sage et plus possible aux déclarations de fonctions de bloc local pour les futures versions standard. Dans ce cas, il est possible d'envisager de déclarer une variable locale dans la fonction de test pour pointer la fonction globale f.