Questions et réponses sur JavaScript

Récemment, SmartSpate a décidé de collecter des questions sur JavaScript et d'y répondre. Le matériel, dont nous publions la traduction, contient un peu plus de deux douzaines de questions sur JavaScript et leurs réponses. La gamme de sujets traités ici est assez large. En particulier, il s'agit des fonctionnalités du langage, des problÚmes rencontrés par les programmeurs lors de l'écriture de code JS, du travail dans le navigateur et dans Node.js.



Question numéro 1. Héritage de prototype


Je me suis habitué aux cours «classiques», mais j'ai décidé d'apprendre JavaScript. J'ai un problÚme pour comprendre le modÚle prototype. Si possible, expliquez, sous forme de modÚles, la possibilité de créer des «classes» en JavaScript, parlez-nous des méthodes et propriétés fermées et ouvertes des classes. Je comprends que beaucoup de choses ont déjà été écrites à ce sujet et qu'en JavaScript, les méthodes et les propriétés des objets sont, par défaut, accessibles au public, mais j'aimerais bien comprendre tout cela. Comment l'héritage de prototype fonctionne-t-il en JavaScript?

▍ RĂ©pondre


L'hĂ©ritage classique n'est pas sans rappeler la façon dont les gens hĂ©ritent des gĂšnes de leurs ancĂȘtres. Les gens ont des capacitĂ©s de base communes, comme marcher et parler. De plus, chaque personne a des particularitĂ©s. Les gens ne peuvent pas changer ce qu'on peut appeler leur «classe», mais ils peuvent changer leurs propres «propriĂ©tĂ©s» dans certaines limites. Dans le mĂȘme temps, les grands-parents, les mĂšres et les pĂšres ne peuvent pas influencer les gĂšnes des enfants ou des petits-enfants au cours de leur vie. Donc, tout est arrangĂ© sur Terre, mais imaginons une autre planĂšte sur laquelle les mĂ©canismes d'hĂ©ritage fonctionnent d'une maniĂšre spĂ©ciale. Disons que certains organismes capables de mutations y utilisent les mĂ©canismes de «transmission tĂ©lĂ©pathique». Cela s'exprime dans le fait qu'ils peuvent modifier les informations gĂ©nĂ©tiques de leurs propres descendants au cours de leur vie.

Prenons l'exemple de l'hĂ©ritage sur cette Ă©trange planĂšte. L'objet PĂšre hĂ©rite des gĂšnes de l'objet Grand-pĂšre et l'objet Fils hĂ©rite des informations gĂ©nĂ©tiques du pĂšre. Chaque habitant de cette planĂšte peut librement muter et changer les gĂšnes de ses descendants. Par exemple, chez "Grand-pĂšre", la peau a une couleur verte. Ce signe est hĂ©ritĂ© du «PĂšre» et du «Fils». Soudain, "Grand-pĂšre" dĂ©cide qu'il est fatiguĂ© d'ĂȘtre vert. Maintenant, il veut ĂȘtre bleu et change la couleur de sa peau (en termes de JS - change le prototype de sa classe), passant "tĂ©lĂ©pathiquement" cette mutation au "PĂšre" et au "Fils". AprĂšs cela, le «pĂšre», croyant que le «grand-pĂšre» avait survĂ©cu Ă  l'esprit, dĂ©cide de changer ses gĂšnes pour qu'il redevienne vert (c'est-Ă -dire qu'il change son propre prototype). Ces changements sont "tĂ©lĂ©pathiquement" transmis au "Fils". En consĂ©quence, le «PĂšre» et le «Fils» ont Ă  nouveau la peau verte. Dans le mĂȘme temps, "Grand-pĂšre" est toujours bleu. Maintenant, peu importe ce qu'il fait avec sa couleur, cela n'affectera personne d'autre. Et tout cela est dĂ» au fait que le "PĂšre" a explicitement dĂ©fini la couleur de sa peau dans son "prototype", et le "Fils" hĂ©rite de cette couleur. Puis le "Fils" pense de cette façon: "Je vais devenir noir. Et que mes descendants hĂ©ritent de la couleur de mon pĂšre. » Pour ce faire, il modifie sa propre propriĂ©tĂ© (et non la propriĂ©tĂ© de son prototype) de telle maniĂšre que sa propriĂ©tĂ© affecterait sa couleur, mais n'affecterait pas ses descendants. Nous exprimons tout cela sous forme de code:

var Grandfather = function () {}; //  Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; //  Father Father.prototype = new Grandfather (); //  - ,        var Son = function () {}; //  Son Son.prototype = new Father (); // Son   Father var u = new Grandfather (); //   Grandfather var f = new Father (); //   Father var s = new Son (); //   Son //     console.log ([u.color, f.color, s.color]); // ["green", "green", "green"] //  Grandfather        Grandfather.prototype.color = 'blue'; console.log ([u.color, f.color, s.color]); // ["blue", "blue", "blue"] //  Father      -   ,     Father.prototype.color = 'green'; //      : // Grandfather.prototype.color = 'green'; console.log ([u.color, f.color, s.color]); // ["blue", "green", "green"] // ,        Grandfather     color,      Grandfather.prototype.color = 'blue'; console.log ([u.color, f.color, s.color]); // ["blue", "green", "green"] //  Son,  ,       Grandfather,    s.color = 'black'; //        console.log ([u.color, f.color, s.color]); // ["blue", "green", "black"] var SonsSon = function () {}; //  SonsSon -   Son SonsSon.prototype = new Son (); //  var ss = new SonsSon (); //   SonsSon //         console.log ([u.color, f.color, s.color, ss.color]); // ["blue", "green", "black", "green"] 

Question numéro 2. Créer des objets


Si vous créez de nouvelles instances d'objets à l'aide du new mot clé, comment pouvez-vous vous protéger contre les erreurs? Voici comment je travaille habituellement:

  1. Je construis toujours des fonctions constructeurs pour qu'elles commencent par une majuscule.
  2. Je vérifie l'exactitude de l'opération en utilisant la construction this instanceof Function_Name (j'essaie de ne pas utiliser la construction du type this instanceof arguments.callee pour des raisons de performances).
  3. Cette approche est similaire à la précédente, mais la comparaison est faite avec window , car je n'aime pas coder en dur les noms des entités et je n'ai pas besoin d'écrire du code pour des environnements autres que le navigateur.

Quel est le modÚle le plus pratique pour créer des objets?

▍ RĂ©pondre


Il est préférable, à la fois sur le plan idéologique et sur la base de la familiarité de cette méthode, de créer des objets à l'aide du new mot clé. Dans ce cas, les fonctions constructeurs doivent recevoir des noms commençant par une majuscule.

Je prĂ©fĂšre m'en tenir aux rĂšgles et ne pas effectuer this vĂ©rifications supplĂ©mentaires sur les constructeurs. Si le constructeur est appelĂ© sans new et que le travail commence dans la portĂ©e globale, cela peut ĂȘtre comparĂ© Ă  «l'auto-tromperie». Dans le mĂȘme temps, je ne recommande en aucun cas de gĂ©rer les situations dans les concepteurs oĂč elles sont appelĂ©es sans le new mot clĂ©. Par exemple, cela peut ressembler Ă  ceci: si le constructeur est appelĂ© sans new , alors, de toute façon, un nouvel objet est créé et retournĂ©. Cette approche est idĂ©ologiquement incorrecte et conduit Ă  des erreurs.
Voici un exemple de travail avec un constructeur.

 var Obj = function () {   "use strict";   this.pew = 100; }; //  let o = new Obj(); o.pew++; console.log(o.pew); //101 // .   Obj (); // TypeError: this is undefined 

Il vaut mieux ne pas utiliser le new mot-clĂ© pour les mĂ©thodes d'usine et pour les cas oĂč il n'y a pas besoin de constructeur, quand il sera plus pratique de crĂ©er un objet en utilisant un objet littĂ©ral. Supposons que le code constructeur indiquĂ© dans l'exemple suivant soit explicitement redondant:

 //    . var Obj = function () {    if (! (this instanceof Obj)) {        return new Obj ();    }    this.pew = 100; }; 

Si, mĂȘme pour crĂ©er un petit objet, vous avez toujours besoin d'un constructeur, il vaut mieux le faire:

 var Obj = function () {    "use strict";    this.pew = 100; }; 

Ici, comme indiqué ci-dessus, du fait que le constructeur fonctionne en mode strict, une erreur se produit lors de son appel sans new .

Question numéro 3. Interception des clics de souris


Comment, en utilisant JavaScript, savoir sur quel bouton de la souris on clique?

▍ RĂ©pondre


Un clic sur les boutons de la souris génÚre des mousedown souris et de mouseup . Dans ce cas, l'événement click est généré uniquement par le bouton gauche de la souris. Dans le gestionnaire d'événements, vous devez vérifier le code situé dans la propriété event.button afin de savoir quel bouton est enfoncé (0 - gauche, 1 - milieu, 2 - droite). Cependant, dans IE, tout semble un peu différent. Prenons un exemple:

 var button = document.getElementById ('button'),              // 0 1 2    buttonMap = ['Left', 'Middle', 'Right'],    handler = function (event) {        event = event || window.event;        alert (buttonMap [event.button] + 'id:' + event.button);    }; if (button.addEventListener) {     button.addEventListener ('mousedown', handler, false); } else {     // IE 0 1 2 3 4     buttonMap = ['???', 'Left', 'Right', '???', 'Middle'];     button.attachEvent ('onmousedown', handler); } 

La bibliothÚque jQuery prend en compte cette fonctionnalité IE, donc lorsque vous l'utilisez dans n'importe quel navigateur, vérifiez simplement la valeur de la propriété event.which au lieu de event.button avec event.button :

 $('button').mousedown(function (event) {   alert(['Left', 'Middle', 'Right'][event.which]); }); 

Question numéro 4. Interception de frappes sur les touches du clavier


Est-il possible d'intercepter, au moyen de JavaScript, en appuyant sur les touches flĂ©chĂ©es (en particulier, en appuyant sur les touches haut et bas), en s'assurant qu'aprĂšs avoir cliquĂ© dessus, le navigateur ne fasse pas dĂ©filer la page? Si cela est possible, quelles sont les caractĂ©ristiques de sa mise en Ɠuvre dans diffĂ©rents navigateurs? Supposons qu'une page s'affiche sur une page qui ne tient pas entiĂšrement Ă  l'Ă©cran. Le dĂ©placement dans les cellules de ce tableau doit ĂȘtre organisĂ© Ă  l'aide des touches flĂ©chĂ©es et il est nĂ©cessaire que le navigateur ne fasse pas dĂ©filer la page lorsque vous cliquez sur ces touches.

▍ RĂ©pondre


Pour implémenter quelque chose comme ça, tout d'abord, vous devez désactiver la réponse systÚme standard aux actions de contrÎle. Par exemple, les touches fléchées et la molette de la souris font défiler la page, un clic droit sur une page fait apparaßtre un menu contextuel, lorsque vous cliquez sur le bouton submit , la fonction form.submit() est form.submit() , lorsque vous cliquez sur le champ de saisie, elle obtient le focus d'entrée, lorsque vous cliquez sur le lien, le navigateur se charge la page à laquelle il mÚne.

Cela peut se faire de différentes maniÚres . Par exemple, comme ceci:

 window.addEventListener("keydown", function(e) {   //  -   if([37, 38, 39, 40].indexOf(e.keyCode) > -1) {       e.preventDefault();   } }, false); 

La page qui suit ne répondra normalement pas aux pressions des touches fléchées.
Une chose importante Ă  noter ici. La mĂ©thode preventDefault() avant l'exĂ©cution de l'action par dĂ©faut. Par exemple, si vous cliquez sur un champ pour l'empĂȘcher d'obtenir le focus d'entrĂ©e, vous devez suspendre le gestionnaire appropriĂ© sur un Ă©vĂ©nement qui se trouve dans la chaĂźne d'Ă©vĂ©nements avant l'action par dĂ©faut. Dans notre cas, il s'agit d'un Ă©vĂ©nement de mousedown :

 $('input').bind ('mousedown', function (event) {   event.preventDefault();   //    return false; }); 

Lorsque vous cliquez sur le champ de saisie, les événements suivants se produisent - dans l'ordre dans lequel ils sont affichés ici:

  1. mousedown
  2. focus (avant cela, un autre objet qui perd le focus déclenchera un événement de blur )
  3. mouseup
  4. click

Si vous essayez d'empĂȘcher l'Ă©lĂ©ment d'obtenir le focus d'entrĂ©e, l'utilisation de gestionnaires d'Ă©vĂ©nements pour cela en commençant par le gestionnaire d'Ă©vĂ©nements focus ne nous aidera pas.

Question numĂ©ro 5. ArrĂȘter l'animation GIF et la touche ESC


Comment gĂ©rer le problĂšme de l'arrĂȘt de l'animation GIF lorsque vous appuyez sur la touche ESC?

▍ RĂ©pondre


Ici, vous pouvez utiliser la mĂȘme approche que nous avons considĂ©rĂ©e ci-dessus. Dans certains navigateurs, appuyer sur la touche ESC arrĂȘte l'animation GIF et le chargement de la page. C'est leur comportement standard, et pour les empĂȘcher de se comporter de cette façon, la mĂ©thode d'Ă©vĂ©nement preventDefault() nous est utile, comme prĂ©cĂ©demment. Le code de la touche ESC est 27.

Question numéro 6. ParenthÚses dans IIFE


Comment la construction à deux parenthÚses est-elle utilisée lors de la déclaration d'une expression de fonction immédiatement invoquée (IIFE)?

▍ RĂ©pondre


Les crochets dans cette situation permettent Ă  l'analyseur de comprendre qu'il y a une fonction devant eux qui doit ĂȘtre exĂ©cutĂ©e. Mais il doit Ă©galement comprendre ce que sont ces crochets - l'opĂ©rateur de regroupement, ou une construction indiquant la nĂ©cessitĂ© d'appeler la fonction. Par exemple, si nous utilisons deux crochets comme indiquĂ© ci-dessous, nous SyntaxError une erreur SyntaxError :

 function () { //  }() 

Cela est dû au fait que la fonction n'a pas de nom (vous devez spécifier leurs noms dans les déclarations de fonction).

Essayons de réécrire ce code, en donnant un nom à la fonction:

 function foo() { //  }() 

Maintenant que la fonction a un nom, cette construction devrait thĂ©oriquement avoir l'air tout Ă  fait normale du point de vue du systĂšme. Mais l'erreur ne disparaĂźt pas, bien qu'elle concerne maintenant l'opĂ©rateur de regroupement, Ă  l'intĂ©rieur duquel il n'y a pas d'expression. Notez que dans ce cas, l'instruction de regroupement est suivie par l'opĂ©rateur de regroupement et non par une sĂ©quence de crochets qui indique au systĂšme que la fonction qui la prĂ©cĂšde doit ĂȘtre appelĂ©e.

IIFE est souvent conçu comme suit:

 (function () {   //  })() 

Mais il existe d'autres façons, dont l'essence est d'indiquer d'une maniĂšre ou d'une autre Ă  l'analyseur qu'avant c'est juste une expression fonctionnelle qui doit ĂȘtre exĂ©cutĂ©e:

 !function () { //  }(); +function () { //  }(); [function() { //  }()]; var a = function () { //  }(); 

IIFE est largement utilisé dans la programmation JavaScript. Par exemple, cette construction est utilisée dans jQuery. Avec son aide, vous pouvez créer des fermetures. En fait, nous parlons du fait que, en utilisant IIFE, le programmeur peut exécuter du code dans la portée locale. Cela aide à protéger la portée mondiale de la pollution et permet d'optimiser l'accÚs aux variables globales. Ces conceptions sont bien réduites.

Question numéro 7. Passer le code en réponse aux demandes


Le serveur, en cours d'interaction AJAX avec le client, dans le corps de la rĂ©ponse, envoie au client une chaĂźne d' alert ('Boom !!!'); . Le client accepte la rĂ©ponse et exĂ©cute ce code Ă  l'aide de la fonction eval() . Comment ça s'appelle? AprĂšs tout, ce qui est contenu dans la rĂ©ponse du serveur n'est ni JSON, ni XML, ni HTML. Que pouvez-vous dire sur l'exĂ©cution sur le client du code qui vient du serveur sous la forme du corps de la rĂ©ponse Ă  une certaine requĂȘte?

▍ RĂ©pondre


En fait, il n'y a pas de nom spĂ©cial pour un tel schĂ©ma d'interaction client-serveur. Et c'est un schĂ©ma d'interaction systĂšme qui est fortement dĂ©conseillĂ©. C'est aussi mauvais que de stocker du code PHP dans une base de donnĂ©es, puis de l'exĂ©cuter Ă  l'aide des mĂ©thodes de langage appropriĂ©es. MĂȘme si nous ne tenons pas compte de considĂ©rations idĂ©ologiques, nous pouvons dire qu'une telle architecture est extrĂȘmement rigide, donc, si le projet oĂč elle est utilisĂ©e, il faudra, au fur et Ă  mesure de son Ă©volution, changer quelque chose, ce ne sera pas facile. Nous voyons ici un exemple d'architecture systĂšme mĂ©diocre lorsque les donnĂ©es sont mĂ©langĂ©es avec du code et des Ă©lĂ©ments d'interface. Afin de changer quelque chose dans un tel systĂšme, vous devez d'abord comprendre les subtilitĂ©s de son architecture complexe, puis, aprĂšs avoir effectuĂ© les modifications, "confondre" Ă  nouveau tout. Je ne parle pas de rĂ©utilisation de code.

Pour simplifier la prise en charge du code, vous devez vous efforcer d'assurer la plus grande sĂ©paration possible des parties du systĂšme et de rĂ©duire le nombre d'interdĂ©pendances de ces parties. Afin d'assurer une faible connectivitĂ© des parties du systĂšme, c'est-Ă -dire de s'assurer qu'un fragment de l'application peut en ĂȘtre extrait ou, avec la moindre complexitĂ©, remplacĂ© par un autre, vous pouvez utiliser des mĂ©canismes d'Ă©vĂ©nements ou des solutions architecturales spĂ©ciales, telles que MVC.

Question numéro 8. Effectuer des opérations lourdes dans le thread principal


Comment organiser l'exécution de certaines commandes gourmandes en ressources en JavaScript et ne pas «suspendre» l'intégralité du script?

▍ RĂ©pondre


JavaScript est un langage monothread. Le code des pages Web est exĂ©cutĂ© dans le mĂȘme thread et les transformations de l'arborescence DOM sont effectuĂ©es. Il y a aussi des minuteries. Chaque fois que vous effectuez des opĂ©rations consommatrices de ressources (cycles, appels Ă  des fonctions "lourdes"), cela conduit Ă  un ralentissement de l'interface utilisateur voire Ă  son blocage complet. Si les opĂ©rations effectuĂ©es n'ont pas une charge particuliĂšrement importante sur le systĂšme, leur impact sur l'interface sera si insignifiant que les utilisateurs ne le remarqueront tout simplement pas. Afin de faire de l'informatique lourde en dehors du thread principal, le concept de web travailleurs a Ă©tĂ© introduit en JavaScript.

Si l'utilisation de travailleurs n'est pas possible, vous devez optimiser les cycles et les fonctions "lourdes". Dans le livre «JavaScript. Optimisation des performances »Nicholas Zakas dit que l'utilisateur ne remarquera rien si le flux de l'interface utilisateur est bloqué pendant 100 ms ou moins.

De cette idĂ©e, nous pouvons conclure que les calculs gourmands en ressources peuvent ĂȘtre divisĂ©s en fragments, dont la mise en Ɠuvre prend un maximum de 100 ms, aprĂšs quoi le thread principal doit ĂȘtre libĂ©rĂ©.

Voici un exemple de code du livre ci-dessus:

 function timedProcessArray(items, process, callback) {   var todo = items.concat();   //    setTimeout(function () {       var start = +new Date();       do {           process(todo.shift());       } while (todo.length > 0 && (+new Date() - start < 50));       if (todo.length > 0){           setTimeout(arguments.callee, 25);       } else {           callback(items);       }   }, 25); } function saveDocument(id) {   var tasks = [openDocument, writeText, closeDocument, updateUI];   timedProcessArray(tasks, [id], function(){       alert("Save completed!");   }); } 

La fonction timedProcessArray() bloque le thread principal pendant 25 ms, exécute une séquence d'actions, puis la libÚre pendant 25 ms, aprÚs quoi ce processus est répété.

Question numĂ©ro 9. À propos du redimensionnement de la fenĂȘtre du navigateur


Puis-je savoir que l'utilisateur a fini de redimensionner la fenĂȘtre du navigateur?

▍ RĂ©pondre


Il n'y a aucun Ă©vĂ©nement spĂ©cial qui vous permet de le savoir. Mais vous pouvez savoir si l'utilisateur redimensionne la fenĂȘtre Ă  l'aide de l'Ă©vĂ©nement onresize . Cette mĂ©thode n'est cependant pas trĂšs prĂ©cise.

Voici un projet de code pour résoudre ce problÚme.

 var time = 0,   timerId,   TIME_ADMISSION = 100; // 0.1  function onresizeend () {   console.log('onresizeend'); }; function resizeWatcher () {   if (+new Date - time >= TIME_ADMISSION) {       onresizeend();       if (timerId) {           window.clearInterval(timerId);           timerId = null;       }   } }; $(window).resize(function () {   if (!timerId) {       timerId = window.setInterval(resizeWatcher, 25);   }   time = +new Date; }); 

Question numĂ©ro 10. Ouverture de nouvelles fenĂȘtres et de nouveaux onglets du navigateur


Comment, Ă  l'aide de la mĂ©thode window.open() , ouvrir une nouvelle fenĂȘtre de navigateur, et non un nouvel onglet?

▍ RĂ©pondre


Le comportement exact de la mĂ©thode window.open() dĂ©pend du navigateur. Opera ouvre toujours de nouveaux onglets (bien qu'ils ressemblent Ă  des fenĂȘtres), Safari ouvre toujours des fenĂȘtres (bien que ce comportement puisse ĂȘtre modifiĂ©). Le comportement de Chrome, Firefox et Internet Explorer peut ĂȘtre contrĂŽlĂ©.

Donc, si un paramĂštre supplĂ©mentaire (position de la fenĂȘtre window.open() passĂ© Ă  la mĂ©thode window.open() , une nouvelle fenĂȘtre sera ouverte:

 window.open('http://www.google.com', '_blank', 'toolbar=0,location=0,menubar=0'); 

Si seul un lien est transmis à cette méthode, un nouvel onglet de navigateur sera ouvert:

 window.open('http://www.google.com'); 

Vous devez souvent ouvrir un nouvel onglet de navigateur. Il peut y avoir des problĂšmes avec cela dans le navigateur Safari. Par dĂ©faut (cela dĂ©pend des paramĂštres), le navigateur, lorsque window.open() est appelĂ©, ouvre une nouvelle fenĂȘtre. Mais si vous cliquez sur le lien, tout en appuyant sur les touches Ctrl + Shift/Meta + Shift , un nouvel onglet s'ouvrira (quels que soient les paramĂštres). Dans l'exemple suivant, nous simulerons l'Ă©vĂ©nement de click qui est dĂ©clenchĂ© lorsque les Ctrl + Shift/Meta + Shift sont enfoncĂ©es:

 function safariOpenWindowInNewTab (href) {    var event = document.createEvent ('MouseEvents'),        mac = (navigator.userAgent.indexOf ('Macintosh')> = 0); //  Ctrl + Shift + LeftClick / Meta + Shift + LeftClick ()    //       event.initMouseEvent (        / * type * / "click",        / * canBubble * / true        / * cancelable * / true,        / * view * / window,        / * detail * / 0,        / * screenX, screenY, clientX, clientY * / 0, 0, 0, 0,        / * ctrlKey * /! mac,        / * altKey * / false,        / * shiftKey * / true        / * metaKey * / mac,        / * button * / 0,        / * relatedTarget * / null    ); //     ,   ,         $ ('<a/>', {'href': href, 'target': '_blank'}) [0] .dispatchEvent (event); } 

Question n ° 11. Copie en profondeur d'objets


Comment organiser efficacement la copie profonde d'objets?

▍ RĂ©pondre


Si l'objet dont vous souhaitez créer la copie (appelons-le oldObject ) ne change pas, il sera plus efficace de le faire via son prototype (cela se fait trÚs rapidement):

 function object(o) {   function F() {}   F.prototype = o;   return new F(); } var newObject = object(oldObject); 

Si vous devez vraiment effectuer l'opĂ©ration de clonage d'un objet, alors le moyen le plus rapide sera rĂ©cursivement, en optimisant ce processus, parcourez ses propriĂ©tĂ©s. Il s'agit peut-ĂȘtre de l'algorithme le plus rapide pour crĂ©er des copies complĂštes d'objets:

 var cloner = {   _clone: function _clone(obj) {       if (obj instanceof Array) {           var out = [];           for (var i = 0, len = obj.length; i < len; i++) {               var value = obj[i];               out[i] = (value !== null && typeof value === "object") ? _clone(value) : value;           }       } else {           var out = {};           for (var key in obj) {               if (obj.hasOwnProperty(key)) {                   var value = obj[key];                   out[key] = (value !== null && typeof value === "object") ? _clone(value) : value;               }           }       }       return out;   }, clone: function(it) {       return this._clone({       it: it       }).it;   } }; var newObject = cloner.clone(oldObject); 

Si vous utilisez jQuery, vous pouvez recourir aux constructions suivantes:

 //   var newObject = jQuery.extend ({}, oldObject); //   var newObject = jQuery.extend (true, {}, oldObject); 

Question numéro 12. Destructeurs JavaScript


Comment créer quelque chose comme un destructeur en JavaScript? Comment gérer le cycle de vie des objets?

▍ RĂ©pondre


En JavaScript, un objet sera supprimé de la mémoire aprÚs la disparition de la derniÚre référence à celui-ci:

 var a = {z: 'z'}; var b = a; var c = a; delete az; delete a; //    a console.log (b, c); // ,  ,    

L'utilisation de quelque chose comme un «destructeur» en JavaScript ne fait qu'effacer le contenu de l'objet, mais pas le supprimer de la mémoire.

Question numéro 13. Traitement des données binaires


Est-il possible de traiter des données binaires en JavaScript? Et si oui, comment?

▍ RĂ©pondre


Si vous devez travailler avec des donnĂ©es binaires dans une application JavaScript, vous pouvez essayer d'utiliser la bibliothĂšque Binary Parser . Mais son code est l'enfer. Dans ES6 +, il y a une suggestion concernant le type StructType (c'est la mĂȘme chose qui est reprĂ©sentĂ©e en C ++ par le type de donnĂ©es composite de struct ). Ce type de donnĂ©es est nĂ©cessaire pour simplifier l'utilisation des donnĂ©es binaires. Travailler avec cela pourrait ressembler Ă  ceci:

 const Point2D = new StructType({ x: uint32, y: uint32 }); const Color = new StructType({ r: uint8, g: uint8, b: uint8 }); const Pixel = new StructType({ point: Point2D, color: Color }); const Triangle = new ArrayType(Pixel, 3); let t = new Triangle([{ point: { x:  0, y: 0 }, color: { r: 255, g: 255, b: 255 } },                     { point: { x: 5, y: 5 }, color: { r: 128, g: 0,   b: 0 } },                     { point: { x: 10, y: 0 }, color: { r: 0,   g: 0, b: 128 } }]); 

Question numéro 14. Modification de variables dans une fonction d'une autre fonction


Comment changer des variables situées dans une fonction d'une autre fonction?

▍ RĂ©pondre


Ici, vous pouvez appliquer plusieurs approches:

  1. Vous pouvez utiliser le lien vers le contexte de la fonction qui nous intéresse (la fonction primer() dans l'exemple suivant) dans la fonction smth() .
  2. Vous pouvez passer une fonction créée dans le contexte de la fonction primer() fonction smth() .

     var primer = function () {    var a, b, c, d, e = {}; smth (function () {        a = 1;        b = 2;        c = 3;        d = 4;    }, e); alert ([a, b, c, d, e.pewpew]); }, smth = function (callback, e) {    callback ();    e.pewpew = "pewpew"; }; primer (); 
  3. Auparavant (avant Firefox 3.6), vous pouviez accéder au contexte en utilisant la propriété __parent__ , mais déjà dans Firefox 4, cette fonctionnalité a été supprimée.

Question numéro 15. Travailler avec des fonctions


Dites-nous comment les fonctions peuvent ĂȘtre appelĂ©es en JavaScript.

▍ RĂ©pondre


Je suppose qu'il n'est pas nécessaire de parler de la façon d'appeler des fonctions, des méthodes et des constructeurs lors d'un travail normal avec eux. Parlons de la façon d'utiliser les méthodes call() et apply() .

Utilisation de call () pour configurer le constructeur d'un objet


 //   function extend (newObj, oldObj) {   function F () {};   F.prototype = oldObj.prototype;   newObj.prototype = new F ();   return newObj }; var Obj = function () {   this.obj_var = 100; }; Obj.prototype.obj_proto_var = 101; var NewObj = function () {   Obj.call (this); //   Obj     obj_var   this.new_obj_var = 102; }; extend (NewObj, Obj) NewObj.prototype.new_obj_proto_var = 103; new NewObj (); // {new_obj_proto_var: 103, new_obj_var: 102, obj_proto_var: 101, obj_var: 100} 

Convertir des objets de type tableau en tableaux


Les objets de type tableau sont similaires aux tableaux JavaScript, mais ils ne le sont pas. En particulier, cela s'exprime dans le fait que ces objets n'ont pas de mĂ©thodes de tableaux ordinaires. Parmi ces objets, par exemple, l'objet arguments des fonctions traditionnelles et les rĂ©sultats de la mĂ©thode getElementsByTagName () peuvent ĂȘtre notĂ©s.

 // document.getElementsByTagName ("div")  ,   ,    , ,  ,        document.getElementsByTagName ("div"). forEach (function (elem) {    // ... }); // TypeError: document.getElementsByTagName ("div"). forEach is not a function //    Array.prototype.slice.call(document.getElementsByTagName("div")).forEach (function (elem) {   // OK }); //        console.log(Array.prototype.slice.call ('pewpew')) // ["p", "e", "w", "p", "e", "w"] //  IE8    

Création d'objets wrapper


Cette technique d'utilisation de call() et apply() vous permet de créer des objets wrapper. , - foo() , bar() .

:

 function bar () {console.log(arguments)} // foo (context, arg1, arg2, ...) function foo () {    var context = arguments [0];    var args = Array.prototype.slice.call (arguments, 1); //     bar    bar.apply (context, args); } 

Function.call.apply() :

 function foo() {   Function.call.apply(bar, arguments); } 

, Function.call.apply() , , foo() , bar .

№16.


, , ?

▍


. , Firefox 3.6, __parent__ , .

№17.


, , , eval() ?

▍


, . , :

 // 1:  eval() (function () {    "use strict";    var globalObject = (0, eval) ("this"); //  :)    return globalObject; } ()); // 2:    (function (global) {    // ... } (window)); // 3:      (function () {    return this; } ()); // 4:            ,       . //  -    "use strict"; (function (global) {    // global }) (this); 

№18.


, JavaScript, , ?

▍


JavaScript - « ». . . , :

 $('#smth').click(function onSmthClick(event) {   if (smth) {       //         event.handlerFunction = onSmthClick;       event.handlerContext = this;       //         //  otherObjectSetSomeEvent   event.handlerFunction          otherObjectSetSomeEvent(event);   } else {       //  -    } }); 

— , . , 2 :

 $('#smth'). click (function handler1 (event) {   if (smth) {       //         leftObjectSetSomeEvent(event, function handler2 (e) {           //  -   e       });   } else {       //  -    } }); function leftObjectSetSomeEvent(event, callback) {   callback (event);   //    } 

№19.


JavaScript ? — , .

▍


click «» DOM. (, , ).

 // jQuery $(window).bind ('click', function (e) {   console.log ('Clicked on', e.target); }); //       $('#pewpew').delegate ('*', 'click', function(e) {   console.log('Clicked on', e.target); }); //     $('#pewpew').delegate('.pewpew', 'click', function (e) {   console.log ('Clicked on element with .pewpew class name'); }); 

№20. XHR-


XHR- jQuery?

▍


, - :

 function xhr(m, u, c, x) { with(new XMLHttpRequest) onreadystatechange = function (x) {   readyState ^ 4 || c(x.target) }, open(m, u), send() } 

- :

 function xhr(m, u, c, x) { with(new(this.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")) onreadystatechange = function (x) {   readyState ^ 4 || c(x) }, open(m, u), send() } 

:

 xhr('get', '//google.com/favicon.ico', function (xhr) { console.dir(xhr) }); 

№21. -


(reflow) (repaint) -?

▍


  1. requestAnimationFrame() , , setInterval() setTimeout() . , , , , , . , JavaScript- CSS- SVG-. , , , , , , . , , .
  2. float- ( ).
  3. DOM. , , , DOM ( ).
  4. — . ( , , ). Voici un exemple:

     //      element.style.left = "150px;"; // ... element.style.color = "green"; //  ,   ,    element.setAttribute ('style', 'color: green; left: 150px'); 
  5. ( ).
  6. — ( style.display = "none" ). , .

, -, . , , , , .

  1. .
  2. DOM- ( — ).
  3. Document.querySelectorAll() firstElementChild .
  4. , document.getElementsByTagName() ( , DOM, ).

№22. Node.js


Node.js, , ?

▍


, ( PHP Apache). , , . Node.js — . , , cluster . (master) - (worker). , .

№23. runInNewContext() Node.js


runInNewContext() Node.js.

▍


. , ( Node.js- Nodester). - , runInNewContext() . , «», . «» , , runInNewContext() .

Résumé


JavaScript . , - , .

Chers lecteurs! , - , , JavaScript , ?

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


All Articles