De quoi JavaScript est-il fait?

Pendant les premières années d'utilisation de JavaScript, je me suis senti comme un imposteur. Même si je pouvais créer des sites Web en utilisant des frameworks, je sentais que je manquais quelque chose. Les interviews JavaScript m'ont fait peur parce que je n'avais pas une compréhension claire des bases de ce langage.



Au fil des ans, j'ai construit un modèle JavaScript mental qui me donne un sentiment de confiance. Ici, je vais partager avec vous une version très concise de ce modèle. Sa structure ressemble à un dictionnaire. Chaque concept est décrit en plusieurs phrases.

En lisant ce document, essayez d'évaluer mentalement dans quelle mesure vous vous sentez confiant à propos de chaque problème abordé ici. Et s'il s'avère que beaucoup de choses d'ici ne vous semblent pas particulièrement familières, je ne vous en blâmerai pas. Mais si c'est vrai, il y a quelque chose à la fin du matériel qui vous aidera à corriger la situation.

Modèle mental JavaScript


  • La valeur. Le concept de sens est un peu abstrait. C'est «quelque chose». Une valeur en JavaScript est identique à un nombre en mathématiques ou un point en géométrie. Lorsque votre programme s'exécute, le monde de ce programme est plein de significations. Des nombres comme 1 , 2 et 420 sont des valeurs. Mais les significations sont d'autres entités. Par exemple, la phrase "Cows go moo" . Certes, tout n'a pas de sens. Un nombre est une valeur, mais une if n'est plus une valeur. Ci-dessous, nous parlerons de différents types de valeurs.

    • Type de valeur. Il existe différents «types» de valeurs. Par exemple, des nombres - comme 420 , des chaînes - comme "Cows go moo" , des objets. Il existe d'autres types de valeurs. Vous pouvez connaître le type de valeur à l'aide de l'opérateur typeof . Par exemple, la commande console.log(typeof 2) affichera un number sur la console.
    • Valeurs primitives. Certaines valeurs ont des types "primitifs". Ce sont des nombres, des chaînes et quelques autres significations. Une propriété intéressante des valeurs primitives est que vous ne pouvez pas créer plus de telles valeurs que dans la langue, vous ne pouvez pas modifier les valeurs primitives existantes. Par exemple, chaque fois que vous utilisez le chiffre 2 dans le code, ce sera la même valeur 2 . Il est impossible de "créer" une valeur de plus 2 dans le programme, ou de faire 2 "tourner" en 3 . Cela est également vrai pour les chaînes.
    • Les valeurs sont null et undefined . Ce sont deux significations particulières. Ils ne sont pas comme les autres, car beaucoup de choses ne peuvent pas être faites avec eux - leur apparence conduit souvent à des erreurs. Habituellement, l'utilisation de null indique qu'une valeur n'a pas été affectée à une variable intentionnellement, et undefined indique qu'une certaine valeur manque par hasard. Cependant, le programmeur décide comment utiliser ces valeurs exactement. Ces valeurs existent du fait que parfois il vaut mieux qu'une erreur se produise lors de l'exécution d'une certaine opération, et il n'arrive pas que l'exécution du programme se poursuive après le "traitement" d'une valeur inexistante.
  • Égalité Comme le concept de sens, le concept d'égalité est l'un des concepts fondamentaux de JavaScript. Nous disons que deux valeurs sont égales si elles ... en fait, je ne dirai pas cela. Si deux valeurs sont égales, cela signifie qu'elles sont une seule et même valeur. Pas deux sens différents, mais un! Par exemple, les égalités "Cows go moo" === "Cows go moo" et 2 === 2 vraies. Et ici, tout est clair: 2 est 2 . Veuillez noter que nous utilisons trois signes égaux, qui représentent le concept ci-dessus d'égalité des valeurs en JavaScript.

    • Égalité stricte. Nous venons de parler de lui dans le paragraphe précédent.
    • Egalité de liens. Et nous venons de parler de lui aussi.
    • Égalité inégale. Oh, mais c'est quelque chose de complètement différent. En JavaScript, la vérification de l'égalité non stricte des valeurs est effectuée à l'aide d'un opérateur composé de deux signes égaux ( == ). Les entités peuvent être reconnues à peu près égales les unes aux autres même si elles sont représentées par des significations différentes qui se ressemblent (quelque chose comme 2 et "2" ). Un opérateur d'égalité non strict a été ajouté à JavaScript dans les premières étapes du développement du langage, pour plus de commodité. Depuis lors, il a été une source de confusion sans fond. Le concept d'égalité lâche ne peut pas être qualifié de fondamental, mais il est une source typique d'erreurs. Vous pouvez apprendre l'opérateur d'égalité non strict un jour de pluie, mais beaucoup essaient simplement de ne pas utiliser l'opérateur == .
  • Littéral. Les littéraux sont utilisés lorsqu'une valeur est référencée en l'écrivant dans le code du programme. Par exemple, 2 est un littéral numérique et "Banana" est un littéral de chaîne.
  • Variable. Les variables vous permettent de référencer des valeurs à l'aide de noms. Par exemple, let message = "Cows go moo" . Après qu'une construction similaire a été utilisée dans le code, où que vous ayez besoin de la phrase "Cows go moo" , vous pouvez écrire juste un message , plutôt que de répéter cette phrase. Plus tard, vous pouvez modifier le message en faisant pointer la variable vers autre chose. Par exemple, en utilisant cette construction: message = "I am the walrus" . Veuillez noter que cela ne change pas le sens lui-même. Cela n'affecte que ce à quoi la variable fait référence. C'est comme «connecter» un nom de variable à autre chose. Au début, la variable était «connectée» à "Cows go moo" , et maintenant à "I am the walrus" .

    • La portée de la variable. Si une seule variable avec le message nom pouvait être utilisée dans tout le programme, ce serait très mauvais. Lorsque nous déclarons une variable, elle n'est disponible que dans une partie du programme. Cette partie est appelée «portée de la variable». Il existe des règles qui décrivent les fonctionnalités de la portée. Vous pouvez généralement identifier la portée d'une variable en recherchant dans quel bloc délimité par des accolades ( {} ) elle est déclarée. Ce bloc peut également être appelé la portée de la variable.
    • Affectation de valeurs aux variables. Lorsque nous écrivons message = "I am the walrus" dans le code, cela conduit au fait que nous modifions la variable de message afin qu'elle pointe vers la valeur "I am the walrus" . Cette opération est appelée affecter une variable à une valeur, ou écrire quelque chose dans une variable, ou définir une variable.
    • Les mots let clés let , const et var . Typiquement, let est le meilleur mot-clé pour déclarer des variables. Si vous voulez vous assurer que rien de nouveau ne peut être écrit dans une variable, vous pouvez utiliser le mot clé const . (Certaines bases de code et commandes sont pédantes à propos de ce problème, forçant tout le monde, si la valeur n'est écrite qu'une seule fois dans la variable, utilisez const .) Essayez de ne pas utiliser le mot clé var , car avec les variables déclarées avec, règles liées à la définition de la portée des variables.
  • Tapez Object . Le type d' Object , dont les entités appartenant sont appelées objets, joue un rôle spécial dans JavaScript. Une caractéristique notable des objets est qu'ils peuvent être associés à d'autres valeurs. Par exemple, l'objet {flavor: "vanilla"} a une propriété de flavor qui pointe vers la valeur de "vanilla" . Les objets peuvent être perçus comme des valeurs indépendantes à partir desquelles des liens vers d'autres valeurs sont tirés.

    • Propriété de l'objet. Une propriété est quelque chose comme une «connexion» qui vient d'un objet et indique une certaine valeur. Cela peut vous rappeler l'idée d'une variable: une propriété a un nom (comme la flavor ), elle pointe vers une valeur (comme "vanilla" ). Mais, contrairement à une variable, les propriétés «vivent» à l'intérieur de l'objet lui-même, et non quelque part dans le code (dans une certaine portée de la variable). Une propriété est considérée comme faisant partie de l'objet et la valeur référencée par la propriété n'est pas considérée comme faisant partie de l'objet.
    • Littéral d'objet. Un littéral objet est un mécanisme qui vous permet de créer des objets en introduisant des constructions appropriées dans le code. Par exemple, il s'agit de {} ou {flavor: "vanilla"} . Entre accolades, plusieurs paires de la : form : , séparées par des virgules, peuvent être déclarées. Cela nous permet de spécifier les valeurs référencées par les propriétés des objets.
    • L'identité des objets. Nous avons déjà dit que 2 est égal à 2 (en d'autres termes - 2 === 2 ), car partout où nous écrivons le nombre 2 , nous «appelons» la même valeur à cet endroit. Mais chaque fois que nous écrivons {} , nous obtenons toujours des valeurs différentes. Par conséquent, un objet de la forme {} pas égal à un autre objet, qui ressemble également à {} . Essayez d'écrire ce qui suit dans la console: {} === {} (le résultat sera false ). Lorsqu'un ordinateur rencontre le numéro 2 dans le code, il fonctionne toujours avec le même diable. Mais les littéraux d'objets sont autre chose. Lorsque l'ordinateur rencontre {} , il crée un nouvel objet, qui est toujours la nouvelle valeur. Comment vérifier l'égalité des objets? Le concept d '"égalité" peut être considéré comme le concept d' "identité de valeurs". Lorsque nous disons: " a et b identiques" - cela signifie que nous voulons dire que a et b indiquent la même valeur (c'est-à-dire, a === b ). Lorsque nous disons que a et b ne b pas identiques, cela signifie que a et b indiquent des valeurs différentes (c'est-à-dire a !== b ).
    • Notation ponctuelle. Lorsque vous devez lire la valeur d'une propriété d'un objet ou écrire quelque chose dans une propriété, vous pouvez utiliser la notation par points ( . ). Par exemple, si la variable iceCream pointe vers un objet dont la flavor propriété contient la chaîne "chocolate" , alors la construction iceCream.flavor nous donnera "chocolate" .
    • Notation entre parenthèses. Parfois, le nom de la propriété de l'objet à adresser n'est pas connu à l'avance. Par exemple, vous devez parfois lire la valeur de la propriété iceCream.flavor , et parfois vous devez lire la valeur de la propriété iceCream.flavor . La notation entre parenthèses ( [] ) vous permet d'accéder aux propriétés des objets en définissant leurs noms à l'aide de variables. Par exemple, supposons qu'il existe une telle variable dans le code: let ourProperty = 'flavor' . Cela signifie qu'un design comme iceCream[ourProperty] nous donnera la valeur "chocolate" . Fait intéressant, vous pouvez utiliser la notation entre parenthèses lors de la création d'objets: { [ourProperty]: "vanilla" } .
    • Mutation. Nous parlons du fait qu'un objet mute (ou change) si quelqu'un écrit une nouvelle valeur dans sa propriété. Par exemple, si nous avons créé un objet let iceCream = {flavor: "vanilla"} , nous pouvons ultérieurement attribuer une nouvelle valeur à la propriété en utilisant iceCream.flavor = "chocolate" . Veuillez noter que même si nous iceCream la variable iceCream à l'aide du mot clé const , cela ne nous empêcherait pas de modifier la propriété de l'objet iceCream.flavor . En effet, l'utilisation de const protège uniquement la variable iceCream contre l'écrasement et nous modifions la propriété de flavor de l'objet référencé par la variable. Certaines personnes ont refusé d'utiliser const uniquement parce que ce mot clé est capable d'induire le programmeur en erreur.
    • Array Un tableau est un objet qui est une collection de certaines valeurs. Les tableaux peuvent être déclarés en utilisant des littéraux de tableau, par exemple, comme ceci: ["banana", "chocolate", "vanilla"] . L'utilisation d'une telle construction conduit à la création d'un objet dont la propriété avec le nom 0 pointe vers la chaîne "banana" , la propriété 1 - vers la chaîne "chocolate" , la propriété 2 - vers la valeur "vanilla" . Il serait fastidieux d'écrire la même chose comme ceci: {0: ..., 1: ..., 2: ...} . Par conséquent, les tableaux sont des structures utiles. Les tableaux ont des mécanismes intégrés conçus pour fonctionner avec leurs éléments. Parmi celles-ci figurent les méthodes de map , de filter et de reduce . Ne vous découragez pas si le nom reduce semble déroutant. Cela semble incompréhensible à tout le monde.
    • Prototype. Que se passe-t-il si vous essayez d'accéder à un objet qui n'existe pas? Par exemple, que se passe-t-il si nous iceCream.taste à iceCream.taste et que l'objet n'a que la propriété de flavor ? Si nous répondons à cette question sans entrer dans les détails, nous pouvons dire que si nous essayons de nous tourner vers une propriété inexistante, nous obtenons une valeur spéciale undefined . Si vous donnez une réponse détaillée à cette question, vous devez commencer par le fait que la plupart des objets en JavaScript ont le soi-disant "prototype". Le prototype d'un objet peut être perçu comme une propriété «cachée» qui indique au système où rechercher la propriété demandée s'il ne se trouve pas dans l'objet lui-même. Dans notre exemple, lorsqu'il s'avère que l'objet iceCream pas de propriété de taste , JavaScript cherchera cette propriété dans le prototype de l'objet, qui est également un objet. Et s'il ne le trouve pas là, alors dans le prototype du prototype, et ainsi de suite. Une valeur undefined ne sera .taste lorsque la fin de la chaîne de prototypes est atteinte et que la propriété .taste est introuvable. Vous devez rarement travailler directement avec ce mécanisme, mais en connaissant les prototypes, vous pouvez comprendre pourquoi l'objet iceCream a une méthode toString que nous n'avons jamais déclarée. Cette méthode est tirée du prototype de l'objet.
  • Fonction. Une fonction est une signification spéciale qui existe dans le seul but de représenter un morceau de code de programme. Les fonctions sont pratiques dans les situations où le programmeur ne souhaite pas écrire constamment le même code. Un «appel» à une fonction qui ressemble à sayHi() indique à l'ordinateur qu'il doit exécuter le code à l'intérieur de la fonction, puis revenir à l'endroit où la fonction a été appelée. JavaScript a plusieurs façons de déclarer des fonctions légèrement différentes.

    • Arguments (ou paramètres) de la fonction. Les arguments vous permettent de transmettre certaines données à la fonction à partir de l'endroit où la fonction est appelée. Par exemple, cela pourrait ressembler à ceci: sayHi("Amelie") . Le comportement des arguments dans une fonction est similaire au comportement des variables. Les mots "paramètres" et "arguments" sont utilisés en fonction de ce qui est discuté exactement - de la déclaration d'une fonction ou de son appel. Bien que la différence de terminologie soit exacte - en pratique, ces termes sont utilisés de manière interchangeable.
    • Expression fonctionnelle. Plus tôt, nous avons écrit des valeurs de chaîne dans des variables. Par exemple, let message = "I am the walrus" . En fait, une fonction peut également être écrite dans une variable: let sayHi = function() { } . Ce qui vient après le signe = est appelé une expression fonctionnelle. Il nous donne une signification spéciale (fonction), qui est un morceau de code. Si nous devons exécuter ce code, nous pouvons appeler la fonction correspondante.
    • Déclaration de fonction. Un programmeur peut être fatigué d'écrire constamment quelque chose comme let sayHi = function() { } . Si c'est le cas, alors une forme plus courte pour décrire une fonction peut être utilisée ici: function sayHi() { } . Cette construction est appelée déclaration de fonction. Au lieu de spécifier un nom de variable sur le côté gauche de l'expression, nous mettons ce nom après le mot clé function . Habituellement, les deux styles de création de fonctions décrits ci-dessus sont interchangeables.
    • Élever les fonctions au sommet de la portée. Habituellement, une variable ne peut être utilisée qu'après avoir été déclarée à l'aide de let ou const , sous le lieu de sa déclaration. Dans le cas de fonctions, cela peut être gênant. Les fonctions peuvent s'appeler. Découvrir lequel doit être créé en premier peut être une tâche ardue. La bonne chose est que lorsque vous utilisez des déclarations de fonctions (et uniquement lorsque vous utilisez cette approche!), L'ordre dans lequel les fonctions sont décrites n'est pas important. Le fait est qu'avec cette approche, les fonctions "montent" à la partie supérieure de la portée. Autrement dit, il s'avère que les fonctions, même lorsque vous essayez de les appeler à partir du code qui précède leur déclaration, sont déjà définies et prêtes à fonctionner.
    • Ce mot-clé. Peut-être que le mot this clé c'est un concept JavaScript qui est le plus souvent mal compris. Ce mot-clé peut être comparé à un argument de fonction spéciale. Mais nous ne transférons pas nous-mêmes ses fonctions. JavaScript passe. La valeur de this dépend de la façon dont la fonction est appelée. Par exemple, lorsque vous appelez une méthode objet en utilisant la notation par points, comme iceCream.eat() , this indiquera ce qui se trouve devant le point. Dans notre exemple, il s'agit d'un objet iceCream . La valeur de this dans une fonction dépend de la façon dont la fonction est appelée et non de l'endroit où elle a été déclarée. Il existe des méthodes spéciales, telles que .bind , .bind et .apply , qui donnent au programmeur la possibilité de contrôler ce qui y entre.
    • Fonctions fléchées. Les fonctions fléchées ressemblent à des expressions fonctionnelles. Ils sont déclarés comme ceci: let sayHi = () => { } . Ils sont compacts et sont souvent utilisés pour les conceptions unifilaires. Les capacités des fonctions fléchées sont plus limitées que celles des fonctions conventionnelles. Par exemple, ils n'ont pas le mot this clé this . Lorsque le mot clé this est utilisé dans une fonction flèche, il est extrait de la fonction dans laquelle la fonction flèche est intégrée. Cela revient à appeler un argument ou une variable à partir d'une fonction imbriquée dans une autre fonction. En pratique, cela signifie que les fonctions fléchées sont utilisées lorsqu'elles veulent que la même valeur qui existe dans le code qui les entoure soit visible en eux.
    • Liaison de this valeur aux fonctions. Habituellement, lier une certaine fonction f à une valeur spécifique de this et à un certain ensemble d'arguments signifie qu'une nouvelle fonction est créée qui appelle la fonction f avec ces valeurs prédéfinies. JavaScript a un mécanisme auxiliaire pour lier des fonctions - la méthode .bind , mais vous pouvez le lier à des fonctions d'autres manières. La liaison était un moyen populaire pour que les fonctions imbriquées «voient» la même valeur que les fonctions qui leur sont externes. Maintenant, les fonctions fléchées sont utilisées dans une situation similaire, par conséquent, la liaison de fonctions est rarement utilisée à notre époque.
    • Pile d'appels Appeler une fonction, c'est comme entrer dans une pièce. Chaque fois que nous appelons une fonction, les variables qu'elle contient sont à nouveau initialisées. Par conséquent, chaque appel de fonction ressemble à la construction d'une nouvelle «pièce» avec un code de fonction. Lorsque la «pièce» est «construite», elle y est «entrée», le code de fonction est exécuté. Variables déclarées dans une fonction "live" dans cette "salle". Lorsque le retour de la fonction est effectué, la «pièce» disparaît avec tout son contenu. Toutes ces «pièces» créées par des appels de fonction peuvent être représentées comme une «tour» haute. Ceci est une pile d'appels. Lorsque nous quittons une certaine fonction, nous arrivons à la fonction, qui est située «en dessous» dans la pile des appels.
    • Récursivité. La récursion est quand une fonction s'appelle elle-même. Cette technique est utile dans les cas où ce qui a déjà été fait par la fonction doit être répété, mais en utilisant d'autres arguments. Par exemple, si nous écrivons un moteur de recherche qui recherche des sites Web, nous pouvons avoir la fonction collectLinks(url) . Cette fonction collecte d'abord les liens situés sur une page d'un site, puis s'appelle elle-même, en passant chacun des liens trouvés à elle-même.Cela se produit jusqu'à ce que toutes les pages d'un site soient visitées. Le danger de récursivité est que, tout à fait par accident, vous pouvez écrire une fonction qui s’invoquera indéfiniment. Certes, si le programme a vraiment une récursion infinie, cela entraînera un débordement de la pile d'appels et l'exécution du programme s'arrêtera avec une erreur stack overflow. La pile déborde car trop d'entrées sur les fonctions appelées y tombent.
    • . — , , . , , — . — , — , , . , .
    • . () — , JavaScript. , , . : . . , setTimeout , … -. , . — . « », , .
    • . , , , , . - , . ? - . — . . , - . JavaScript, , . «». JavaScript, , , , .


JavaScript , . . JavaScript. , . JavaScript. — Just JavaScript . , , JavaScript.

! JavaScript?

Source: https://habr.com/ru/post/fr482472/


All Articles