Bonjour à tous! Fin septembre, un nouveau
volet du cours
«Développeur Fullstack JavaScript» débutera chez
OTUS . En prévision du début des cours, nous souhaitons partager avec vous un article d'auteur préparé spécialement pour les étudiants du cours.
Auteur de l'article: Pavel Yakupov
Aperçu Je tiens à noter tout de suite que dans cet article les sujets qui sont familiers aux «ninjas» sont examinés, et l'article vise plus à faire mieux comprendre aux débutants certaines des nuances de la langue, et à ne pas se perdre dans les tâches qu'ils donnent souvent lors d'une interview - après tout, tels Les tâches n'ont rien à voir avec un vrai développement, et ceux qui les donnent, le plus souvent de cette façon, essaient de comprendre à quel point vous connaissez JavaScript.

Types de mémoire de référence
Comment les données sont-elles stockées en JavaScript exactement? De nombreux cours de programmation commencent à expliquer avec le classique: une variable est une sorte de «boîte» dans laquelle nous stockons des données. Lesquelles, pour les langues avec typage dynamique, il semble que cela n'a pas d'importance: l'interprète lui-même "avale" tous les types de données et change dynamiquement le type si nécessaire, et vous ne devriez pas penser aux types de variables et à la façon dont elles sont traitées. Ce qui bien sûr est faux, et donc nous allons commencer la discussion d'aujourd'hui avec des fonctionnalités qui s'échappent souvent: comment les variables sont stockées en JavaScript - sous forme de primitives (copies) ou sous forme de liens.
Nous allons immédiatement lister les types de variables qui peuvent être stockées sous forme de primitives: ce sont
boolean
,
null
,
undefined
,
Number
,
String
,
Symbol
,
BigInt
. Lorsque nous rencontrons des variables déclarées séparément avec ce type de données, nous devons nous rappeler que lors de l'initialisation initiale, elles créent une cellule mémoire - et qu'elles peuvent être affectées, copiées, transférées et renvoyées par valeur.
Le reste de JavaScript repose sur des zones de mémoire référencées. Pourquoi sont-ils nécessaires? Les créateurs de la langue ont essayé de créer une langue dans laquelle la mémoire serait utilisée aussi économiquement que possible (et ce n'était absolument pas nouveau à l'époque). Pour illustrer, imaginez que vous devez vous souvenir des noms de trois nouveaux collègues de travail - des noms complètement nouveaux, et pour améliorer la comparaison, vos nouveaux collègues d'Inde ou de Chine avec des noms inhabituels pour vous. Imaginez maintenant que vos collègues soient appelés comme vous et vos deux meilleurs amis à l'école. Dans quelle situation sera-t-il plus facile de se souvenir? Ici, la mémoire d'une personne et d'un ordinateur fonctionne de manière similaire. Voici quelques exemples spécifiques:
let x = 15;
Ainsi, si vous rencontrez une tâche similaire lors d'une interview, essayez de comprendre immédiatement quel type de données est devant vous - d'où elles proviennent et comment elles ont obtenu la valeur, en tant que type primitif ou en tant que référence.

Travail de contexte
Afin de comprendre exactement comment le contexte fonctionne dans JS, vous devez étudier quelques points:
- Niveau de visibilité global / local.
- Différence de contexte lors de l'initialisation des variables dans la portée globale / locale.
- Fonctions fléchées.
Il était une fois, de retour dans ES5, tout était assez simple: il n'y avait qu'une déclaration de variable utilisant var, qui lorsqu'elle était déclarée dans le flux du programme était considérée comme globale (ce qui signifiait que la variable était affectée en tant que propriété à un objet global, tel que
window
ou
global
). Ensuite,
let
et
const
sont arrivés sur la scène, qui se comportent quelque peu différemment: ils ne sont pas affectés à l'objet global et sont stockés en mémoire différemment, en se concentrant sur la portée du bloc. Maintenant, var est déjà considéré comme obsolète, car son utilisation peut entraîner un colmatage de la portée globale et, en outre,
let
semble beaucoup plus prévisible.
1. Donc, pour comprendre, il vaut la peine de comprendre clairement quelle est la portée de JavaScript (portée). Si une variable est déclarée dans la portée globale à l'aide de la directive
let
, elle n'est pas affectée à l'objet
window
, mais est enregistrée globalement.
Passons aux tâches qui débutent le plus souvent sur des questions contextuelles lors de l'entretien.
//: ? let x = 15; function foo(){ let x = 13; return x; } console.log(x)// 15 foo(); console.log(x)// x = foo(); console.log(x)// return ,
2. En même temps, tous les débutants ne savent pas comment l'interpréteur JavaScript lit le code: en fait, il le lit deux fois, la première fois qu'il lit le code des fonctions déclarées comme déclaration de fonction (et est prêt à les exécuter à la seconde, lecture et exécution réelles ) Une autre petite astuce est liée à
var
et
let
: la première fois qu'une variable avec la directive
var
est lue, elle est définie sur
undefined
. Mais avec
let
son appel prématuré n'est pas possible du tout:
console.log(x); console.log(y) var x = 42; let y = 38;
3. Les fonctions fléchées qui sont apparues dans ES6 ont rapidement gagné en popularité - elles ont été rapidement adoptées par les programmeurs sur
Node.js (en raison d'une mise à jour rapide du moteur) et
React (en raison des fonctionnalités de la bibliothèque et de l'utilisation inévitable de Babel). En ce qui concerne le contexte, les fonctions fléchées respectent la règle suivante: elles ne s'y lient pas. Nous illustrons ceci:
var x = 4; var y = 4; function mult(){ return this.x * this.y; } let foo = mult.bind(this); console.log(foo()); let muliply = ()=>x*y; console.log(muliply()); /* x y let, function declaration */

Types de données et ce qui s'applique à
Disons tout de suite: un tableau est essentiellement un objet, et en JavaScript, ce n'est pas la première variante d'un objet - Map, WeakSet, Set et collections le confirment.
Ainsi, un tableau est un objet, et sa différence par rapport à un objet normal dans JS réside principalement dans une plus grande vitesse en raison de l'optimisation de l'indexation, et d'autre part dans l'héritage de Array.prototype, qui fournit un plus grand ensemble de méthodes, c'est pourquoi Big Brother »
Object.prototype
.
console.log(typeof({})) console.log(typeof([])) console.log(typeof(new Set)) console.log(typeof(new Map)) //
Le suivant dans la file d'attente des bizarreries des types de données est
null
. Si vous demandez à JavaScript quel type de données est nul, nous obtenons une réponse assez claire. Cependant, ici, cela ne se passera pas sans quelques astuces:
let x = null; console.log(typeof(x)); //! , null objet, ? console.log(x instanceof Object.prototype.constructor); //false // ! )
Il convient de rappeler que
null
est un type de données spécial - bien que le début de l'exemple précédent pointait strictement vers un autre. Pour mieux comprendre pourquoi ce type particulier a été ajouté au langage, il me semble qu'il vaut la peine d'explorer les bases de la syntaxe C ++ ou C #.
Et bien sûr, dans les entretiens, on rencontre souvent une telle tâche, dont la particularité est liée au typage dynamique:
console.log(null==undefined);//true console.log(null===undefined);// false
Un grand nombre d'astuces sont associées à la conversion de type lors de la comparaison dans JS; nous ne sommes pas physiquement en mesure de les apporter ici. Nous vous recommandons de vous référer à
"What the hell JavaScript" .

Caractéristiques illogiques laissées dans le langage pendant le processus de développement
Ajout de lignes. En fait, l'ajout de chaînes avec des nombres ne peut pas être attribué à des erreurs dans le développement du langage, cependant, dans le contexte de JavaScript, cela a conduit à des exemples bien connus qui ne sont pas considérés comme suffisamment logiques:
codepen.io/pen/?editors=0011 let x = 15; let y = "15"; console.log(x+y);// "" console.log(xy); //
Le fait que plus ajoute simplement des lignes avec des nombres est relativement illogique, mais vous devez juste vous en souvenir. Cela peut être particulièrement inhabituel car les deux autres langages interprétés qui sont populaires et largement utilisés dans le développement Web - PHP et Python - ne lancent pas de telles astuces avec l'ajout de chaînes et de nombres et se comportent de manière beaucoup plus prévisible dans de telles opérations.
Des exemples similaires sont moins connus, par exemple avec NaN:
console.log(NaN == NaN); //false console.log(NaN > NaN); //false console.log(NaN < NaN); //false … ... , NaN? console.log(typeof(NaN)); // number
Souvent, NaN apporte des surprises désagréables si, par exemple, vous avez mal configuré la vérification de type.
L'exemple avec 0.1 +0.2 est beaucoup plus célèbre - car cette erreur est liée au format IEEE 754, qui est également utilisé, par exemple, dans un tel Python «mathématique».
Nous incluons également un bug moins connu avec le numéro Epsilon, pour la raison qui se situe dans la même veine:
console.log(0.1+0.2)// 0.30000000000000004 console.log(Number.EPSILON);// 2.220446049250313e-16 console.log(Number.EPSILON + 2.1) // 2.1000000000000005
Et des questions un peu plus compliquées:
Object.prototype.toString.call([])// ? // -> '[object Array]' Object.prototype.toString.call(new Date) // Date? // -> '[object Date]'

Étapes de traitement des événements
De nombreux débutants ne comprennent pas les événements du navigateur. Souvent, même inconnus sont les principes les plus élémentaires du fonctionnement des événements du navigateur - interception, ascension et événements par défaut. La chose la plus mystérieuse du point de vue d'un débutant est l'émergence d'un événement qui, sans doute, se justifie au départ pose question. La fenêtre contextuelle fonctionne comme suit: lorsque vous cliquez sur un élément DOM imbriqué, l'événement se déclenche non seulement sur celui-ci, mais également sur le parent, si un gestionnaire avec un tel événement a également été installé sur le parent.
Dans le cas où un événement survient, nous pouvons être amenés à l'annuler.
// , function MouseOn(e){ this.style.color = "red"; e.stopPropagation(); // }
De plus, pour les débutants, il est souvent difficile d'annuler les événements qui se produisent par défaut. Ceci est particulièrement important lors du développement de formulaires - car la validation des formulaires, par exemple, doit être effectuée à la fois côté client et côté serveur:
codepen.io/isakura313/pen/GRKMdaR?editors=0010 document.querySelector(".button-form").addEventListener( 'click', function(e){ e.preventDefault(); console.log(' . , ') } )
L'annulation de la surface d'un événement peut également entraîner des problèmes: par exemple, vous pouvez créer une soi-disant «zone morte» dans laquelle la chose nécessaire ne fonctionnera pas - par exemple, un événement d'un élément qui n'a «pas de chance» d'être proche.
Merci à tous pour votre attention! Voici quelques liens utiles à partir desquels vous pouvez tirer de nombreuses informations utiles:
C’est tout. Nous vous attendons au
webinaire gratuit , qui se tiendra le 12 septembre.