Fragen und Antworten zu JavaScript

Vor kurzem hat SmartSpate beschlossen, Fragen zu JavaScript zu sammeln und zu beantworten. Das Material, dessen Übersetzung wir veröffentlichen, enthält etwas mehr als zwei Dutzend Fragen zu JavaScript und die Antworten darauf. Das hier behandelte Themenspektrum ist recht breit. Dies sind insbesondere Funktionen der Sprache, Probleme, auf die Programmierer beim Schreiben von JS-Code stoßen, die im Browser und in Node.js arbeiten.



Frage Nummer 1. Vererbung von Prototypen


Ich habe mich an die „klassischen“ Klassen gewöhnt, aber beschlossen, JavaScript zu lernen. Ich habe ein Problem beim Verständnis des Prototypmodells. Wenn möglich, erläutern Sie in Form von Vorlagen die Möglichkeit, „Klassen“ in JavaScript zu erstellen, und informieren Sie uns über die geschlossenen und offenen Methoden und Eigenschaften von Klassen. Ich verstehe, dass bereits viel darüber geschrieben wurde und dass in JavaScript die Methoden und Eigenschaften von Objekten standardmäßig öffentlich verfügbar sind, aber ich möchte dies alles richtig verstehen. Wie funktioniert die Vererbung von Prototypen in JavaScript?

▍ Antwort


Die klassische Vererbung erinnert sehr daran, wie Menschen die Gene ihrer Vorfahren erben. Menschen haben einige gemeinsame Grundfähigkeiten wie Gehen und Sprechen. Darüber hinaus hat jede Person einige Besonderheiten. Menschen können ihre "Klasse" nicht ändern, aber sie können ihre eigenen "Eigenschaften" innerhalb bestimmter Grenzen ändern. Gleichzeitig können Großeltern, Mütter und Väter die Gene von Kindern oder Enkelkindern im Laufe ihres Lebens nicht beeinflussen. Also ist alles auf der Erde angeordnet, aber stellen wir uns einen anderen Planeten vor, auf dem Vererbungsmechanismen auf besondere Weise funktionieren. Angenommen, einige mutationsfähige Organismen nutzen dort die Mechanismen der "telepathischen Vererbung". Dies drückt sich darin aus, dass sie im Laufe ihres Lebens die genetische Information ihrer eigenen Nachkommen verändern können.

Betrachten Sie das Beispiel der Vererbung auf diesem seltsamen Planeten. Das Vater-Objekt erbt Gene vom Großvater-Objekt und das Sohn-Objekt erbt genetische Informationen vom Vater. Jeder Bewohner dieses Planeten kann die Gene seiner Nachkommen frei mutieren und verändern. Zum Beispiel hat bei "Großvater" die Haut eine grüne Farbe. Dieses Zeichen wird vom „Vater“ und vom „Sohn“ geerbt. Plötzlich entscheidet "Großvater", dass er es satt hat, grün zu sein. Jetzt möchte er blau sein und seine Hautfarbe ändern (in Bezug auf JS - ändert den Prototyp seiner Klasse), indem er diese Mutation „telepathisch“ an den „Vater“ und den „Sohn“ weitergibt. Danach beschließt „Vater“, der glaubt, dass „Großvater“ aus dem Kopf überlebt hat, seine Gene so zu ändern, dass er wieder grün wird (dh er ändert seinen eigenen Prototyp). Diese Änderungen werden "telepathisch" an den "Sohn" übertragen. Infolgedessen haben sowohl der „Vater“ als auch der „Sohn“ wieder eine grüne Haut. Gleichzeitig ist "Großvater" immer noch blau. Egal was er mit seiner Farbe macht, es wird niemanden betreffen. Und das alles ist darauf zurückzuführen, dass der "Vater" die Farbe seiner Haut in seinem "Prototyp" explizit festgelegt hat und der "Sohn" diese Farbe erbt. Dann denkt der "Sohn" so: "Ich werde schwarz. Und lassen Sie meine Nachkommen Farbe von meinem Vater erben. “ Zu diesem Zweck ändert er sein eigenes Eigentum (und nicht das Eigentum seines Prototyps) so, dass sein Eigentum seine Farbe, aber nicht seine Nachkommen beeinflusst. Wir drücken dies alles in Form von Code aus:

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"] 

Frage Nummer 2. Objekte erstellen


Wenn Sie mit dem new Schlüsselwort neue Instanzen von Objekten erstellen, wie können Sie sich dann vor Fehlern schützen? So arbeite ich normalerweise:

  1. Ich konstruiere Konstruktorfunktionen immer so, dass sie mit einem Großbuchstaben beginnen.
  2. Ich überprüfe die Richtigkeit der Operation mit dem Konstrukt this instanceof Function_Name (aus Leistungsgründen versuche ich, das Konstrukt des Typs this instanceof arguments.callee nicht zu verwenden).
  3. Dieser Ansatz ähnelt dem vorherigen, wird jedoch mit window verglichen, da ich die Namen von Entitäten nicht gerne hart codiere und keinen Code für andere Umgebungen als den Browser schreiben muss.

Was ist das bequemste Modell zum Erstellen von Objekten?

▍ Antwort


Sowohl ideologisch als auch basierend auf der Vertrautheit dieser Methode ist es am besten, Objekte mit dem new Schlüsselwort zu erstellen. In diesem Fall müssen den Konstruktorfunktionen Namen gegeben werden, die mit einem Großbuchstaben beginnen.

Ich halte mich lieber an die Regeln und führe keine zusätzlichen Überprüfungen der Konstruktoren durch. Wenn der Konstruktor ohne new aufgerufen wird und die Arbeit im globalen Bereich beginnt, kann dies mit "Selbsttäuschung" verglichen werden. Gleichzeitig empfehle ich keinesfalls, dass Sie Situationen in Designern behandeln, in denen sie ohne das new Schlüsselwort aufgerufen werden. Zum Beispiel könnte es so aussehen: Wenn der Konstruktor ohne new aufgerufen wird, wird ohnehin ein neues Objekt erstellt und zurückgegeben. Dieser Ansatz ist ideologisch falsch und führt zu Fehlern.
Hier ist ein Beispiel für die Arbeit mit einem Konstruktor.

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

Es ist besser, das new Schlüsselwort nicht für Factory-Methoden zu verwenden und in Fällen, in denen kein Konstruktor erforderlich ist, wenn es bequemer ist, ein Objekt mit einem Objektliteral zu erstellen. Angenommen, der im folgenden Beispiel gezeigte Konstruktorcode ist explizit redundant:

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

Wenn Sie auch zum Erstellen eines kleinen Objekts noch einen Konstruktor benötigen, ist dies besser:

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

Wie oben gezeigt, tritt hier ein Fehler auf, wenn der Konstruktor im strengen Modus arbeitet, wenn er ohne new aufgerufen wird.

Frage Nummer 3. Abfangen von Mausklicks


Wie können Sie mithilfe von JavaScript feststellen, auf welche Maustaste geklickt wird?

▍ Antwort


Durch Klicken auf die Maustasten werden mousedown und mouseup generiert. In diesem Fall wird das click nur mit der linken Maustaste generiert. In der Ereignisbehandlungsroutine müssen Sie den Code in der Eigenschaft event.button überprüfen, um herauszufinden, welche Schaltfläche gedrückt wird (0 - links, 1 - Mitte, 2 - rechts). Im IE sieht jedoch alles etwas anders aus. Betrachten Sie ein Beispiel:

 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); } 

Die jQuery-Bibliothek berücksichtigt diese IE-Funktion. Wenn Sie sie also in einem beliebigen Browser verwenden, überprüfen Sie einfach den Wert der event.which Eigenschaft, anstatt mit event.button :

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

Frage Nummer 4. Abfangen von Tastenanschlägen auf Tastaturtasten


Ist es möglich, mit JavaScript die Pfeiltasten (insbesondere die Abwärts- und Aufwärts-Tasten) abzufangen, sodass der Browser nach dem Klicken nicht durch die Seite rollt? Wenn dies möglich ist, welche Funktionen bietet es dann, dies in verschiedenen Browsern zu implementieren? Angenommen, eine Seite wird auf einer Seite angezeigt, die nicht vollständig auf den Bildschirm passt. Das Bewegen durch die Zellen dieser Tabelle muss mit den Pfeiltasten organisiert werden, und es ist erforderlich, dass der Browser beim Klicken auf diese Tasten nicht durch die Seite blättert.

▍ Antwort


Um so etwas zu implementieren, müssen Sie zunächst die Standardsystemantwort auf Steueraktionen deaktivieren. Zum Beispiel scrollen die Pfeiltasten und das Mausrad durch die Seite. Wenn Sie mit der rechten Maustaste auf eine Seite klicken, wird ein Kontextmenü form.submit() Wenn Sie auf die Schaltfläche " form.submit() klicken, wird die Funktion " form.submit() . Wenn Sie auf das Eingabefeld klicken, wird der Eingabefokus angezeigt. Wenn Sie auf den Link klicken, wird der Browser geladen die Seite, zu der es führt.

Dies kann auf verschiedene Arten erfolgen . Zum Beispiel so:

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

Die Seite danach reagiert normalerweise nicht auf Pfeiltasten.
Eine wichtige Sache, die hier zu beachten ist. Die Methode preventDefault() bevor die Standardaktion ausgeführt wird. Wenn Sie beispielsweise auf ein Feld klicken, um zu verhindern, dass es den Eingabefokus erhält, müssen Sie den entsprechenden Handler vor der Standardaktion an ein Ereignis in der Ereigniskette hängen. In unserem Fall handelt es sich um ein mousedown Ereignis:

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

Wenn Sie auf das Eingabefeld klicken, treten folgende Ereignisse auf - in der Reihenfolge, in der sie hier angezeigt werden:

  1. mousedown
  2. focus (vorher löst ein anderes Objekt, das den Fokus verliert, ein blur )
  3. mouseup
  4. click

Wenn Sie versuchen, zu verhindern, dass das Element einen Eingabefokus erhält, hilft es uns nicht, Event-Handler zu verwenden, die mit dem focus Event-Handler beginnen.

Frage Nummer 5. Stoppen Sie die GIF-Animation und die ESC-Taste


Wie gehe ich mit dem Problem um, die GIF-Animation beim Drücken der ESC-Taste zu stoppen?

▍ Antwort


Hier können Sie den gleichen Ansatz verwenden, den wir oben betrachtet haben. In einigen Browsern werden durch Drücken der ESC-Taste die GIF-Animation und das Laden von Seiten gestoppt. Dies ist ihr Standardverhalten. Um zu verhindern, dass sie sich auf diese Weise verhalten, ist die Ereignismethode preventDefault() für uns nach wie vor hilfreich. Der ESC-Schlüsselcode lautet 27.

Frage Nummer 6. Klammern in IIFE


Wie werden die beiden Klammern verwendet, um einen sofort aufgerufenen Funktionsausdruck (IIFE) zu deklarieren?

▍ Antwort


Klammern in dieser Situation ermöglichen es dem Parser zu verstehen, dass vor ihnen eine Funktion ausgeführt werden muss. Er muss aber auch verstehen, was diese Klammern sind - der Gruppierungsoperator oder eine Konstruktion, die angibt, dass die Funktion aufgerufen werden muss. Wenn wir beispielsweise zwei Klammern verwenden, wie unten gezeigt, tritt ein SyntaxError Fehler auf:

 function () { //  }() 

Dies liegt daran, dass die Funktion keinen Namen hat (Sie müssen ihre Namen in Funktionsdeklarationen angeben).

Versuchen wir, diesen Code neu zu schreiben und der Funktion einen Namen zu geben:

 function foo() { //  }() 

Nun, da die Funktion einen Namen hat, sollte diese Konstruktion aus Sicht des Systems theoretisch ganz normal aussehen. Der Fehler verschwindet jedoch nicht, obwohl er jetzt mit dem Gruppierungsoperator zu tun hat, in dem sich kein Ausdruck befindet. Beachten Sie, dass in diesem Fall der Gruppierungsanweisung der Gruppierungsoperator folgt und keine Folge von Klammern, die dem System mitteilt, dass die vorhergehende Funktion aufgerufen werden muss.

Oft ist IIFE wie folgt aufgebaut:

 (function () {   //  })() 

Es gibt aber auch andere Möglichkeiten, deren Kern es ist, dem Parser irgendwie anzuzeigen, dass es sich zuvor nur um einen funktionalen Ausdruck handelt, der ausgeführt werden muss:

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

IIFE werden häufig in der JavaScript-Programmierung verwendet. Dieses Konstrukt wird beispielsweise in jQuery verwendet. Mit seiner Hilfe können Sie Verschlüsse erstellen. In der Tat sprechen wir über die Tatsache, dass der Programmierer mit IIFE Code im lokalen Bereich ausführen kann. Dies trägt zum Schutz des globalen Bereichs vor Verschmutzung bei und ermöglicht die Optimierung des Zugriffs auf globale Variablen. Solche Designs sind gut minimiert.

Frage Nummer 7. Code als Antwort auf Anfragen übergeben


Der Server sendet alert ('Boom !!!'); der AJAX-Interaktion mit dem Client im Hauptteil der Antwort dem Client eine alert ('Boom !!!'); . Der Client akzeptiert die Antwort und führt diesen Code mit der Funktion eval() aus. Wie heißt es? Schließlich ist in der Serverantwort nicht JSON, nicht XML und nicht HTML enthalten. Was können Sie über die Ausführung des vom Server kommenden Clients auf dem Client in Form des Hauptteils der Antwort auf eine bestimmte Anforderung sagen?

▍ Antwort


Tatsächlich gibt es keinen speziellen Namen für ein solches Schema für die Client-Server-Interaktion. Und dies ist ein Systeminteraktionsschema, von dem dringend abgeraten wird. Dies ist genauso schlecht wie das Speichern von PHP-Code in einer Datenbank und das anschließende Ausführen mit geeigneten Sprachmethoden. Selbst wenn wir ideologische Überlegungen nicht berücksichtigen, können wir sagen, dass eine solche Architektur äußerst unflexibel ist. Wenn also das Projekt, in dem sie verwendet wird, während der Entwicklung notwendig ist, etwas zu ändern, wird dies nicht einfach sein. Hier sehen wir ein Beispiel für eine schlechte Systemarchitektur, wenn Daten mit Code- und Schnittstellenelementen gemischt werden. Um etwas in einem solchen System zu ändern, müssen Sie zuerst die Feinheiten seiner komplizierten Architektur verstehen und dann nach den Änderungen wieder alles „verwirren“. Ich spreche nicht von Code-Wiederverwendung.

Um die Codeunterstützung zu vereinfachen, müssen Sie eine größtmögliche Trennung der Teile des Systems anstreben und die Anzahl der Abhängigkeiten dieser Teile verringern. Um eine schlechte Konnektivität von Teilen des Systems sicherzustellen, dh um sicherzustellen, dass ein Fragment der Anwendung daraus extrahiert oder mit der geringsten Komplexität durch ein anderes ersetzt werden kann, können Sie Ereignismechanismen oder spezielle Architekturlösungen wie MVC verwenden.

Frage Nummer 8. Durchführen schwerer Operationen im Hauptfaden


Wie kann man die Ausführung bestimmter ressourcenintensiver Befehle in JavaScript organisieren und nicht das gesamte Skript "aussetzen"?

▍ Antwort


JavaScript ist eine Single-Threaded-Sprache. Webseitencode wird im selben Thread ausgeführt und DOM-Baumtransformationen werden durchgeführt. Es gibt auch Timer. Jedes Mal, wenn Sie einige ressourcenintensive Vorgänge ausführen (Zyklen, Aufrufe "schwerer" Funktionen), führt dies zu einer Verlangsamung der Benutzeroberfläche oder sogar zu deren vollständiger Blockierung. Wenn die ausgeführten Vorgänge das System nicht besonders stark belasten, sind ihre Auswirkungen auf die Benutzeroberfläche so gering, dass Benutzer sie einfach nicht bemerken. Um Heavy Computing außerhalb des Hauptthreads zu erstellen, wurde das Konzept der Web-Worker in JavaScript eingeführt.

Wenn der Einsatz von Arbeitern nicht möglich ist, müssen Sie die Zyklen und "schweren" Funktionen optimieren. In dem Buch „JavaScript. Leistungsoptimierung “Nicholas Zakas sagt, dass der Benutzer nichts bemerkt, wenn der Fluss der Benutzeroberfläche für 100 ms oder weniger blockiert wird.

Aus dieser Idee können wir schließen, dass ressourcenintensive Berechnungen in Fragmente unterteilt werden können, deren Implementierung maximal 100 ms dauert. Danach muss der Hauptthread freigegeben werden.

Hier ist ein Beispielcode aus dem obigen Buch:

 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!");   }); } 

Die Funktion timedProcessArray() blockiert den Hauptthread für 25 ms, führt eine Folge von Aktionen aus und gibt sie dann für 25 ms frei. Danach wird dieser Vorgang wiederholt.

Frage Nummer 9. Informationen zum Ändern der Größe des Browserfensters


Kann ich irgendwie herausfinden, dass der Benutzer die Größe des Browserfensters geändert hat?

▍ Antwort


Es gibt kein besonderes Ereignis, bei dem Sie es herausfinden können. Sie können jedoch mithilfe des Ereignisses onresize herausfinden, ob der Benutzer die Fenstergröße onresize . Diese Methode ist jedoch nicht sehr genau.

Hier ist ein Codeentwurf zur Lösung dieses Problems.

 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; }); 

Frage Nummer 10. Öffnen neuer Browserfenster und Registerkarten


Wie kann mit der Methode window.open() ein neues Browserfenster und kein neuer Tab geöffnet werden?

▍ Antwort


Wie genau sich die window.open() -Methode verhält, hängt vom Browser ab. Opera öffnet immer neue Registerkarten (obwohl sie wie Fenster aussehen), Safari öffnet immer Fenster (obwohl dieses Verhalten geändert werden kann). Das Verhalten von Chrome, Firefox und Internet Explorer kann gesteuert werden.

Wenn also ein zusätzlicher Parameter (Fensterposition window.open() an die window.open() -Methode übergeben wird, wird ein neues Fenster geöffnet:

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

Wenn nur ein Link zu dieser Methode übergeben wird, wird eine neue Browser-Registerkarte geöffnet:

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

Oft müssen Sie eine neue Browser-Registerkarte öffnen. Möglicherweise gibt es Probleme damit im Safari-Browser. Standardmäßig (abhängig von den Einstellungen) öffnet der Browser beim window.open() ein neues Fenster. Wenn Sie jedoch auf den Link klicken und die Tasten Ctrl + Shift/Meta + Shift drücken, wird eine neue Registerkarte geöffnet (unabhängig von den Einstellungen). Im folgenden Beispiel simulieren wir das Klickereignis, das click wird, wenn die Tasten Ctrl + Shift/Meta + Shift gedrückt werden:

 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); } 

Frage Nr. 11. Objekte tief kopieren


Wie kann man das tiefe Kopieren von Objekten effektiv organisieren?

▍ Antwort


Wenn sich das Objekt, dessen Kopie Sie erstellen möchten (nennen wir es oldObject ), nicht ändert, ist es am effektivsten, dies über den Prototyp zu tun (dies geschieht sehr schnell):

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

Wenn Sie den Vorgang des Klonens eines Objekts wirklich ausführen müssen, ist der schnellste Weg rekursiv, diesen Prozess zu optimieren und seine Eigenschaften durchzugehen. Vielleicht ist dies der schnellste Algorithmus zum Erstellen tiefer Kopien von Objekten:

 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); 

Wenn Sie jQuery verwenden, können Sie auf die folgenden Konstrukte zurückgreifen:

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

Frage Nummer 12. JavaScript-Destruktoren


Wie erstelle ich so etwas wie einen Destruktor in JavaScript? Wie verwalte ich den Lebenszyklus von Objekten?

▍ Antwort


In JavaScript wird ein Objekt aus dem Speicher gelöscht, nachdem der letzte Verweis darauf verschwunden ist:

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

Die Verwendung eines „Destruktors“ in JavaScript führt nur zum Löschen des Inhalts des Objekts, nicht jedoch zum Löschen aus dem Speicher.

Frage Nummer 13. Binäre Datenverarbeitung


Ist es möglich, Binärdaten in JavaScript zu verarbeiten? Und wenn ja, wie?

▍ Antwort


Wenn Sie in einer JavaScript-Anwendung mit Binärdaten arbeiten müssen, können Sie versuchen, die Binary Parser- Bibliothek zu verwenden. Aber ihr Code ist die Hölle. In ES6 + gibt es einen Vorschlag zum StructType Typ (dies ist dasselbe, was in C ++ durch den zusammengesetzten Datentyp von struct ). Dieser Datentyp wird benötigt, um das Arbeiten mit Binärdaten zu vereinfachen. Die Arbeit damit könnte ungefähr so ​​aussehen:

 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 } }]); 

Frage Nummer 14. Ändern von Variablen in einer Funktion von einer anderen Funktion


Wie ändere ich Variablen in einer Funktion von einer anderen Funktion?

▍ Antwort


Hier können Sie verschiedene Ansätze anwenden:

  1. Sie können den Link zum Kontext der für uns interessanten Funktion (die Funktion primer() im folgenden Beispiel) in der Funktion smth() verwenden.
  2. Sie können eine im Kontext der Funktion primer() Funktion an die Funktion 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. Früher (vor Firefox 3.6) konnten Sie mit der Eigenschaft __parent__ zum Kontext __parent__ , aber bereits in Firefox 4 wurde diese Funktion entfernt.

Frage Nummer 15. Mit Funktionen arbeiten


Sagen Sie uns, wie Funktionen in JavaScript aufgerufen werden können.

▍ Antwort


Ich nehme an, es besteht keine Notwendigkeit, darüber zu sprechen, wie Funktionen, Methoden und Konstruktoren während der normalen Arbeit mit ihnen aufgerufen werden. Lassen Sie uns über die Verwendung der Methoden call() und apply() sprechen.

Verwenden von call () zum Konfigurieren des Konstruktors eines Objekts


 //   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} 

Konvertieren Sie Array-ähnliche Objekte in Arrays


Array-ähnliche Objekte ähneln JavaScript-Arrays, sind es jedoch nicht. Dies drückt sich insbesondere darin aus, dass solche Objekte keine Methoden für gewöhnliche Arrays haben. Unter solchen Objekten können beispielsweise das arguments traditioneller Funktionen und die Ergebnisse der Methode getElementsByTagName () notiert werden.

 // 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    

Erstellen von Wrapper-Objekten


Mit dieser Technik der Verwendung von call() und apply() können Sie Wrapper-Objekte erstellen. , - 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. — . ( , , ). Hier ist ein Beispiel:

     //      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() .

Zusammenfassung


JavaScript . , - , .

Liebe Leser! , - , , JavaScript , ?

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


All Articles