Héritage des prototypes
À l'exception de null
et undefined
, chaque type de données primitives possède une
prototype, un wrapper d'objet correspondant qui fournit des méthodes pour travailler
avec des valeurs. Lorsqu'une recherche de méthode ou de propriété est appelée sur une primitive,
JavaScript encapsule la primitive en arrière-plan et appelle la méthode ou
effectue plutôt la recherche de propriétés sur l'objet wrapper.
Par exemple, un littéral de chaîne n'a pas de méthode propre, mais vous pouvez appeler la fonction
Méthode .toUpperCase()
dessus grâce à l'objet String
correspondant
wrapper:
"this is a string literal".toUpperCase();
> THIS IS A STRING LITERAL
C'est ce qu'on appelle l'héritage prototypique, qui consiste à hériter des propriétés et des méthodes. à partir du constructeur correspondant à une valeur.
Number.prototype
> Number { 0 }
> constructor: function Number()
> toExponential: function toExponential()
> toFixed: function toFixed()
> toLocaleString: function toLocaleString()
> toPrecision: function toPrecision()
> toString: function toString()
> valueOf: function valueOf()
> <prototype>: Object { … }
Vous pouvez créer des primitives à l'aide de ces constructeurs, au lieu de vous contenter de définir
en fonction de leur valeur. Par exemple, l'utilisation du constructeur String
crée un
un objet de chaîne, et non un littéral de chaîne: un objet qui contient non seulement notre chaîne,
mais toutes les propriétés et méthodes héritées du constructeur.
const myString = new String( "I'm a string." );
myString;
> String { "I'm a string." }
typeof myString;
> "object"
myString.valueOf();
> "I'm a string."
Pour la plupart, les objets résultants se comportent comme les valeurs que nous avons utilisées pour
les définir. Par exemple, même si vous définissez une valeur numérique à l'aide de la méthode
Le constructeur new Number
génère un objet contenant toutes les méthodes et
du prototype Number
, vous pouvez utiliser des opérateurs mathématiques sur
ces objets comme vous le feriez avec des littéraux numériques:
const numberOne = new Number(1);
const numberTwo = new Number(2);
numberOne;
> Number { 1 }
typeof numberOne;
> "object"
numberTwo;
> Number { 2 }
typeof numberTwo;
> "object"
numberOne + numberTwo;
> 3
Vous aurez très rarement besoin d'utiliser ces constructeurs, car JavaScript est intégré l'héritage prototypique signifie qu'ils n'apportent aucun avantage pratique. Création... Les primitives utilisant des constructeurs peuvent également entraîner des résultats inattendus, le résultat est un objet, et non un simple littéral:
let stringLiteral = "String literal."
typeof stringLiteral;
> "string"
let stringObject = new String( "String object." );
stringObject
> "object"
Cela peut compliquer l'utilisation d'opérateurs de comparaison stricts:
const myStringLiteral = "My string";
const myStringObject = new String( "My string" );
myStringLiteral === "My string";
> true
myStringObject === "My string";
> false
Insertion automatique de point-virgule (ASI)
Lors de l'analyse d'un script, les interpréteurs JavaScript peuvent utiliser une fonctionnalité appelée l'insertion automatique de points-virgules (ASI) pour essayer de corriger les instances ou des points-virgules. Si l'analyseur JavaScript rencontre un jeton non autorisé, il tente d'ajouter un point-virgule avant ce jeton pour corriger l'erreur de syntaxe potentielle, car tant qu'une ou plusieurs des conditions suivantes sont remplies:
- Ce jeton est séparé du jeton précédent par un saut de ligne.
- Ce jeton est
}
. - Le jeton précédent est
)
, et le point-virgule inséré correspond à la fin point-virgule d'une instructiondo
...while
.
Pour en savoir plus, consultez les règles ASI.
Par exemple, le fait d'omettre des points-virgules après les instructions suivantes n'entraînera pas erreur de syntaxe à cause d'ASI:
const myVariable = 2
myVariable + 3
> 5
Toutefois, ASI ne peut pas prendre en compte plusieurs instructions sur la même ligne. Si vous rédigez plusieurs instructions sur la même ligne, en veillant à les séparer par des Points-virgules:
const myVariable = 2 myVariable + 3
> Uncaught SyntaxError: unexpected token: identifier
const myVariable = 2; myVariable + 3;
> 5
ASI est une tentative de correction d'erreur, et non une sorte de flexibilité syntaxique conçue en JavaScript. Assurez-vous d'utiliser des points-virgules lorsque cela est approprié afin de ne pas compter pour produire un code correct.
Mode strict
Les normes qui régissent l'écriture du code JavaScript ont bien évolué tout ce qui avait été pris en compte lors de la conception initiale du langage. Chaque nouvelle modification apportée à Le comportement attendu de JavaScript doit éviter de provoquer des erreurs sur les sites Web plus anciens.
ES5 résout certains problèmes de longue date liés à la sémantique JavaScript sans
de casser les implémentations existantes
en introduisant un "mode strict", un moyen d'opter
dans un ensemble plus restrictif de règles de langage, soit pour l'intégralité d'un script,
fonction individuelle. Pour activer le mode strict, utilisez le littéral de chaîne
"use strict"
, suivi d'un point-virgule, sur la première ligne d'un script ou
:
"use strict";
function myFunction() {
"use strict";
}
Le mode strict empêche certaines données "non sécurisées" ou des fonctionnalités obsolètes, génère
des erreurs explicites à la place des modes "silencieux" courants et interdit l'utilisation
qui pourraient entrer en conflit
avec de futures fonctionnalités linguistiques. Par exemple, début
décisions de conception autour d'une portée variable
les développeurs sont plus susceptibles
de "polluer" par erreur le champ d'application global
déclarer une variable, quel que soit le contexte qui la contient, en omettant le
Mot clé var
:
(function() {
mySloppyGlobal = true;
}());
mySloppyGlobal;
> true
Les environnements d'exécution JavaScript modernes ne peuvent pas corriger ce comportement, sans risque endommager tout site Web qui s'appuie sur ce dernier, de manière erronée ou délibérée. Le JavaScript moderne l'empêche plutôt par les développeurs d'opter pour pour les nouvelles tâches, et l'activation du mode strict par défaut uniquement dans le contexte nouvelles fonctionnalités linguistiques qui n'affecteront pas les anciennes implémentations:
(function() {
"use strict";
mySloppyGlobal = true;
}());
> Uncaught ReferenceError: assignment to undeclared variable mySloppyGlobal
Vous devez écrire "use strict"
en tant que
littéral de chaîne.
Un littéral de modèle
(use strict
) ne fonctionnera pas. Vous devez également inclure "use strict"
avant tout
code exécutable dans son contexte prévu. Sinon, l'interprète l'ignore.
(function() {
"use strict";
let myVariable = "String.";
console.log( myVariable );
sloppyGlobal = true;
}());
> "String."
> Uncaught ReferenceError: assignment to undeclared variable sloppyGlobal
(function() {
let myVariable = "String.";
"use strict";
console.log( myVariable );
sloppyGlobal = true;
}());
> "String." // Because there was code prior to "use strict", this variable still pollutes the global scope
Par référence, par valeur
Toute variable, y compris les propriétés d'un objet, paramètres de fonction et éléments d'une tableau, set ; ou map, peut contenir soit une primitive, ou une valeur de référence.
Lorsqu'une valeur primitive est attribuée d'une variable à une autre, le code JavaScript crée une copie de cette valeur et l'attribue à la variable.
Lorsque vous attribuez un objet (instances de classe, tableaux et fonctions) à une variable, au lieu de créer une copie de cet objet, celle-ci contient une à la position stockée en mémoire de l'objet. Pour cette raison, la modification Un objet référencé par une variable modifie l'objet référencé, et pas seulement une valeur contenue dans cette variable. Par exemple, si vous initialisez un nouveau par une variable contenant une référence d'objet, puis utilisez la nouvelle variable pour ajouter une propriété à cet objet, la propriété et sa valeur sont ajoutées à l'objet d'origine:
const myObject = {};
const myObjectReference = myObject;
myObjectReference.myProperty = true;
myObject;
> Object { myProperty: true }
Ceci est important non seulement pour modifier des objets, mais aussi pour effectuer
comparaisons, car une égalité stricte entre les objets exige que les deux variables
faire référence au même objet pour renvoyer la valeur true
. Ils ne peuvent pas faire référence
objets différents, même s'ils sont structurellement identiques:
const myObject = {};
const myReferencedObject = myObject;
const myNewObject = {};
myObject === myNewObject;
> false
myObject === myReferencedObject;
> true
Allocation de mémoire
JavaScript utilise la gestion automatique de la mémoire, ce qui signifie que la mémoire n'a pas besoin explicitement allouées ou libérées pendant le développement. Alors que les détails des moteurs JavaScript approches de la gestion de la mémoire vont au-delà le champ d'application de ce module, c'est-à-dire comprendre comment la mémoire est allouée le contexte pour travailler avec des valeurs de référence.
Il y a deux « zones » en mémoire: la "pile" et le "tas". La pile stocke des données statiques (valeurs primitives et références aux objets), car le l'espace requis pour stocker ces données peut être alloué avant que le s'exécute. Le tas de mémoire stocke des objets, qui nécessitent un espace alloué dynamiquement car leur taille peut changer lors de l'exécution. La mémoire est libérée par un processus appelée "récupération de mémoire", ce qui supprime les objets sans référence mémoire.
Thread principal
JavaScript est un langage fondamentalement monothread avec une approche "synchrone" modèle d'exécution, ce qui signifie qu'il ne peut exécuter qu'une seule tâche à la fois. Ce contexte d'exécution séquentielle est appelé thread principal.
Le thread principal est partagé par d'autres tâches du navigateur, comme l'analyse HTML, le rendu de certaines parties de la page, l'exécution d'animations CSS la gestion des interactions des utilisateurs, des plus simples (comme la mise en surbrillance de texte) à le complexe (comme interagir avec des éléments du formulaire). Les fournisseurs de navigateurs ont trouvé des moyens d'optimiser les tâches effectuées par le thread principal, mais des tâches plus complexes les scripts peuvent encore utiliser une trop grande partie des ressources du thread principal et avoir un impact global les performances de la page.
Certaines tâches peuvent être exécutées d'arrière-plan appelés nœuds de calcul Web, avec quelques restrictions:
- Les threads de calcul ne peuvent agir que sur des fichiers JavaScript autonomes.
- L'accès à la fenêtre et à l'interface utilisateur du navigateur a été considérablement réduit, voire inexistant.
- Leur communication avec le thread principal est limitée.
Ces limitations en font un outil idéal pour les tâches ciblées et gourmandes en ressources pourrait occuper le thread principal.
Pile d'appel
La structure de données utilisée pour gérer les « contextes d’exécution », le code étant activement exécutées : il s'agit d'une liste appelée pile d'appel (généralement juste "la pile"). Lorsqu'un script est exécuté pour la première fois, l'interpréteur JavaScript crée un "contexte d'exécution globale" et le transfère dans la pile d'appel, les instructions de ce contexte global, exécutées une par une, de haut en bas en bas. Lorsque l'interpréteur rencontre un appel de fonction lors de l'exécution de la global, il transmet un "contexte d'exécution de la fonction" pour cet appel en haut de la pile, met en pause le contexte d'exécution global et exécute la fonction le contexte d'exécution.
Chaque fois qu'une fonction est appelée, le contexte d'exécution de cette fonction est le suivant : en haut de la pile, juste au-dessus du contexte d'exécution actuel. La pile d'appel opère sur un principe de type "premier entré, premier sorti" ce qui signifie que les plus l'appel de fonction récent, qui a le plus haut dans la pile, est exécuté et continue jusqu'à ce qu'il soit résolu. Lorsque cette fonction est terminée, l'interpréteur la supprime de la pile d'appel et le contexte d'exécution contenant cet appel de fonction redevient l'élément le plus élevé de la pile et reprend l'exécution.
Ces contextes d'exécution capturent toutes les valeurs nécessaires à leur exécution. Ils
établissent également les variables et les fonctions disponibles dans le cadre
en fonction de son contexte parent, puis déterminez et définissez la valeur de la
Mot clé this
dans le contexte de la fonction.
Boucle d'événements et file d'attente de rappel
Cette exécution séquentielle signifie que les tâches asynchrones qui incluent des rappels
comme extraire des données d'un serveur, répondre à une interaction de l'utilisateur,
ou que vous attendiez un minuteur défini sur setTimeout
ou setInterval
, soit bloqué
le thread principal jusqu'à ce que cette tâche soit terminée ou qu'il interrompe de manière inattendue
contexte d'exécution actuel au moment où le contexte d'exécution de la fonction de rappel
est ajoutée à la pile. Pour résoudre ce problème, JavaScript gère les tâches asynchrones
à l'aide d'un "modèle de simultanéité" basé sur les événements composée de la "boucle d'événements" et
"file d'attente de rappel" (parfois appelée "file d'attente de messages").
Lorsqu'une tâche asynchrone est exécutée sur le thread principal, le rappel le contexte d'exécution de la fonction est placé dans la file d'attente de rappel, et non au-dessus de pile d'appel. La boucle d'événements est un modèle parfois appelé réacteur, qui, en continu, interroge l'état de la pile d'appel et de la file d'attente de rappel. S'il y a des tâches dans la file d'attente de rappel et la boucle d'événements déterminent que la pile d'appel est vide, les tâches de la file d'attente de rappel sont transférées une par une vers la pile exécuté.