Wenig bekannte JavaScript-Funktionen

JavaScript wird oft als die einfachste Sprache für Anfänger bezeichnet, in der Programmierung, die am schwierigsten zu beherrschen ist. Der Autor des Materials, dessen Übersetzung wir veröffentlichen, sagt, dass er dieser Aussage nur zustimmen kann. Die Sache ist, dass JS eine sehr alte und sehr flexible Sprache ist. Es ist voll von mysteriösen syntaktischen Konstrukten und veralteten Funktionen, die es immer noch unterstützt.

Bild

Heute werden wir über die wenig bekannten JavaScript-Funktionen und -Optionen für ihre praktische Anwendung sprechen.

JavaScript ist immer etwas Neues


Ich arbeite seit vielen Jahren mit JavaScript und stoße ständig auf etwas, von dem ich nicht vermutete, dass es es gibt. Hier habe ich versucht, ähnliche wenig bekannte Merkmale der Sprache aufzulisten. Im strengen Modus funktionieren einige von ihnen nicht, im normalen Modus sind sie jedoch vollständig korrekte JS-Codebeispiele. Es sollte angemerkt werden, dass ich nicht davon ausgehe, den Lesern zu raten, all dies in Betrieb zu nehmen. Obwohl das, worüber ich sprechen werde, für Sie sehr interessant erscheint, können Sie all dies nutzen, wenn Sie in einem Team arbeiten und, gelinde gesagt, Ihre Kollegen überraschen.

→ Den Code, den wir hier diskutieren , finden Sie hier.

Bitte beachten Sie, dass ich Dinge wie das Auslösen von Variablen, Schließungen, Proxy-Objekten, Prototyp-Vererbung, Async / Warten, Generatoren und dergleichen nicht berücksichtigt habe. Obwohl diese Merkmale der Sprache schwer zu verstehen sind, sind sie nicht bekannt.

Leerer Operator


JavaScript hat einen unären void Operator. Möglicherweise sind Sie in Form von void(0) oder void 0 . Sein einziger Zweck ist es, den Ausdruck zu seiner Rechten zu berechnen und undefined . 0 hier wird es einfach verwendet, weil es üblich ist, obwohl dies nicht notwendig ist, und hier können Sie jeden gültigen Ausdruck verwenden. True, dieser Operator gibt auf jeden Fall undefined .

 //  void void 0                  // undefined void (0)                // undefined void 'abc'              // undefined void {}                 // undefined void (1 === 1)          // undefined void (1 !== 1)          // undefined void anyfunction()      // undefined 

Warum der Sprache, die zur Rückgabe von undefined dient, ein spezielles Schlüsselwort hinzufügen, wenn Sie nur den Standardwert undefined ? Ist es nicht so, gibt es eine gewisse Redundanz?

Wie sich herausstellte, konnte vor dem Erscheinen des ES5-Standards in den meisten Browsern einem Standardwert von undefined ein neuer Wert zugewiesen werden. Angenommen, Sie könnten diesen Befehl erfolgreich ausführen: undefined = "abc" . Infolgedessen ist ein undefined Wert möglicherweise nicht so, wie er sein sollte. In jenen Tagen ermöglichte uns die Verwendung von void , das Vertrauen in die Verwendung des echten undefined zu gewährleisten.

Klammern beim Aufrufen von Konstruktoren sind optional


Die Klammern, die nach dem Klassennamen eingefügt werden und den Konstruktor aufrufen, sind vollständig optional (es sei denn, der Konstruktor muss Argumente übergeben).

Im folgenden Beispiel wirkt sich das Vorhandensein oder Fehlen von Klammern nicht auf den korrekten Betrieb des Programms aus.

 //     const date = new Date() const month = new Date().getMonth() const myInstance = new MyClass() //     const date = new Date const month = (new Date).getMonth() const myInstance = new MyClass 

Klammern können nicht mit IIFE verwendet werden


Die IIFE-Syntax erschien mir immer seltsam. Warum gibt es all diese Klammern?

Wie sich herausstellte, werden die Klammern nur benötigt, um dem JavaScript-Parser mitzuteilen, dass ein Code ein Funktionsausdruck ist und kein falscher Versuch, eine Funktion zu deklarieren. Wenn wir diese Tatsache kennen, können wir verstehen, dass es viele Möglichkeiten gibt, die Klammern, in denen IIFE eingeschlossen ist, zu entfernen und gleichzeitig Arbeitscode zu schreiben.

 // IIFE (function () { console.log('Normal IIFE called') })() // Normal IIFE called void function () { console.log('Cool IIFE called') }() // Cool IIFE called 

Hier teilt der void Operator dem Parser mit, dass der darauf folgende Code ein Funktionsausdruck ist. Dies ermöglicht es, die Klammern um die Funktionsdeklaration zu entfernen. Übrigens können Sie hier jeden unären Operator verwenden ( void , + , ! , - usw.), und der Code funktioniert weiterhin. Ist das nicht wunderbar?

Wenn Sie jedoch ein aufmerksamer Leser sind, fragen Sie sich möglicherweise, ob der unäre Operator das von IIFE zurückgegebene Ergebnis beeinflusst. In der Tat so wie es ist. Das Gute ist jedoch, dass Sie keine Klammern um IIFE benötigen, wenn Sie das Ergebnis von IIFE benötigen, das Sie beispielsweise in einer Variablen speichern. Hier ist ein Beispiel.

 // IIFE,    let result = (function () { // ... -  return 'Victor Sully' })() console.log(result) // Victor Sully let result1 = function () { // ... -  return 'Nathan Drake' }() console.log(result1) // Nathan Drake 

Die geschweiften Klammern um das erste IIFE verbessern nur die Lesbarkeit des Codes, ohne dessen Betrieb zu beeinträchtigen.

Wenn Sie IIFE besser verstehen möchten, schauen Sie sich dieses Material an.

Bau mit


Wissen Sie, dass JavaScript ein with Konstrukt hat, das Ausdrucksblöcke unterstützt? Es sieht so aus:

 with (object)  statement //       with (object) {  statement  statement  ... } 

Das Konstrukt with fügt alle Eigenschaften des Objekts hinzu, das in der Bereichskette übergeben wird, die beim Ausführen der Befehle verwendet wird.

 //    with const person = { firstname: 'Nathan', lastname: 'Drake', age: 29 } with (person) { console.log(`${firstname} ${lastname} is ${age} years old`) } // Nathan Drake is 29 years old 

with mag wie ein tolles Werkzeug erscheinen. Es scheint sogar noch besser zu sein als die neuen Funktionen von JS für die Objektzerstörung , aber tatsächlich ist es nicht so.

Die with Konstruktion ist veraltet und wird nicht zur Verwendung empfohlen. Im strengen Modus ist seine Verwendung verboten. Es stellt sich heraus, dass Blöcke Leistungs- und Sicherheitsprobleme verursachen.

Funktionskonstruktor


Die Verwendung des function ist nicht die einzige Möglichkeit, eine neue Funktion zu definieren. Sie können Funktionen dynamisch mit dem Function und dem new Operator definieren. So sieht es aus.

 //  Function const multiply = new Function('x', 'y', 'return x*y') multiply(2,3) // 6 

Das letzte an den Konstruktor übergebene Argument ist eine Zeichenfolge mit dem Funktionscode. Zwei weitere Argumente sind Funktionsparameter.

Es ist interessant festzustellen, dass der Function das "übergeordnete" Element aller Konstruktoren in JavaScript ist. Sogar der Object ist ein Function . Und der native Function ist auch Function . Infolgedessen gibt ein Aufruf vom Typ object.constructor.constructor... der für ein JS-Objekt ausreichend oft ausgeführt wurde, den Function als Ergebnis zurück.

Feature-Eigenschaften


Wir alle wissen, dass Funktionen in JavaScript erstklassige Objekte sind. Daher hindert uns niemand daran, Funktionen neue Eigenschaften hinzuzufügen. Dies ist völlig normal, wird aber selten verwendet.

Wann kann das nötig sein?

In der Tat gibt es mehrere Situationen, in denen diese Funktion nützlich sein kann. Betrachten Sie sie.

▍ Benutzerdefinierte Funktionen


Angenommen, wir haben eine greet() Funktion. Sie muss je nach den verwendeten regionalen Einstellungen unterschiedliche Begrüßungsnachrichten anzeigen. Diese Einstellungen können in einer Variablen außerhalb der Funktion gespeichert werden. Darüber hinaus verfügt die Funktion möglicherweise über eine Eigenschaft, die diese Einstellungen definiert, insbesondere die Spracheinstellungen des Benutzers. Wir werden den zweiten Ansatz verwenden.

 //  ,   function greet () { if (greet.locale === 'fr') {   console.log('Bonjour!') } else if (greet.locale === 'es') {   console.log('Hola!') } else {   console.log('Hello!') } } greet() // Hello! greet.locale = 'fr' greet() // Bonjour! 

▍Funktionen mit statischen Variablen


Hier ist ein weiteres ähnliches Beispiel. Angenommen, wir müssen einen bestimmten Generator implementieren, der eine Folge von geordneten Zahlen erzeugt. In solchen Situationen werden normalerweise statische Zählervariablen in Klassen oder IIFE verwendet, um Informationen über die zuletzt generierte Zahl zu speichern. Mit diesem Ansatz beschränken wir den Zugang zum Schalter und verhindern die Verschmutzung des globalen Bereichs durch zusätzliche Variablen.

Aber was ist, wenn wir Flexibilität brauchen, wenn wir den Wert eines solchen Zählers lesen oder sogar ändern müssen und den globalen Bereich nicht verstopfen?

Natürlich können Sie eine Klasse mit der entsprechenden Variablen und mit Methoden erstellen, um damit zu arbeiten. Oder Sie können sich nicht mit solchen Dingen beschäftigen und nur die Eigenschaften von Funktionen nutzen.

 //  ,   function generateNumber () { if (!generateNumber.counter) {   generateNumber.counter = 0 } return ++generateNumber.counter } console.log(generateNumber()) // 1 console.log(generateNumber()) // 2 console.log('current counter value: ', generateNumber.counter) // current counter value: 2 generateNumber.counter = 10 console.log('current counter value: ', generateNumber.counter) // current counter value: 10 console.log(generateNumber()) // 11 

Argumente Objekteigenschaften


Ich bin sicher, die meisten von Ihnen wissen, dass Funktionen ein arguments . Dies ist ein Array-ähnliches Objekt, auf das in allen Funktionen zugegriffen werden kann (mit Ausnahme von Pfeilfunktionen, die kein eigenes arguments ). Es enthält eine Liste von Argumenten, die beim Aufruf an die Funktion übergeben wurden. Darüber hinaus hat es einige interessante Eigenschaften:

  • arguments.callee enthält einen Link zur aktuellen Funktion.
  • arguments.caller enthält einen Verweis auf die Funktion, die die aktuelle Funktion aufgerufen hat.

Betrachten Sie ein Beispiel.

 //  callee  caller  arguments const myFunction = function () { console.log('Current function: ', arguments.callee.name) console.log('Invoked by function: ', arguments.callee.caller.name) } void function main () { myFunction() } () // Current function: myFunction // Invoked by function: main 

Der ES5-Standard verbietet die Verwendung von callee und callee im strengen Modus, ist jedoch in vielen mit JavaScript kompilierten Programmtexten, z. B. in Bibliotheken, noch weit verbreitet. Daher ist es nützlich, über sie Bescheid zu wissen.

Tagged Template Literals


Wenn Sie etwas mit JavaScript-Programmierung zu tun haben, haben Sie sicherlich von Vorlagenliteralen gehört . Vorlagenliterale sind eine der vielen großen Innovationen des ES6-Standards. Kennen Sie jedoch markierte Vorlagenliterale?

 //    `Hello ${username}!` //    myTag`Hello ${username}!` 

Mit markierten Vorlagenliteralen kann der Entwickler steuern, wie aus dem Vorlagenliteral eine Zeichenfolge wird. Dies erfolgt mithilfe spezieller Tags. Ein Tag ist nur der Name einer Parserfunktion, die ein Array von Zeichenfolgen und Werten empfängt, die von einem Zeichenfolgenmuster interpretiert werden. Bei Verwendung einer Tag-Funktion wird erwartet, dass die fertige Zeichenfolge zurückgegeben wird.

Im folgenden Beispiel interpretiert unser Tag " highlight die Daten eines Vorlagenliterals und bettet diese Daten in eine fertige Zeile ein. Platzieren Sie sie im HTML-Tag <mark> , um sie auszuwählen, wenn dieser Text auf einer Webseite angezeigt wird.

 //    function highlight(strings, ...values) { //  i -      let result = '' strings.forEach((str, i) => {   result += str   if (values[i]) {     result += `<mark>${values[i]}</mark>`   } }) return result } const author = 'Henry Avery' const statement = `I am a man of fortune & I must seek my fortune` const quote = highlight`${author} once said, ${statement}` // <mark>Henry Avery</mark> once said, <mark>I am a man of fortune // & I must seek my fortune</mark> 

Interessante Möglichkeiten zur Verwendung dieser Funktion finden Sie in vielen Bibliotheken. Hier einige Beispiele:


Getter und Setter in ES5


JavaScript-Objekte sind größtenteils ziemlich einfach. Angenommen, wir haben ein user und versuchen, mit dem Konstrukt user.age auf seine Eigenschaft age user.age . Wenn bei diesem Ansatz diese Eigenschaft definiert ist, erhalten wir ihren Wert, und wenn sie nicht definiert ist, werden wir undefined . Alles ist sehr einfach.

Das Arbeiten mit Eigenschaften muss jedoch gar nicht so primitiv sein. JS-Objekte implementieren das Konzept von Gettern und Setzern. Anstatt den Wert einer Eigenschaft des Objekts direkt zurückzugeben, können wir unsere eigene Getter-Funktion schreiben, die das zurückgibt, was wir für notwendig halten. Gleiches gilt für das Schreiben neuer Werte in die Eigenschaften mithilfe von Setterfunktionen.

Mit Gettern und Setzern können Sie erweiterte Schemata für die Arbeit mit Eigenschaften implementieren. Beim Lesen oder Schreiben von Eigenschaften können Sie die Konzepte virtueller Felder verwenden, die Werte von Feldern überprüfen und beim Schreiben oder Lesen können einige nützliche Nebenwirkungen auftreten.

 //    const user = { firstName: 'Nathan', lastName: 'Drake', // fullname -    get fullName() {   return this.firstName + ' ' + this.lastName }, //      set age(value) {   if (isNaN(value)) throw Error('Age has to be a number')   this._age = Number(value) }, get age() {   return this._age } } console.log(user.fullName) // Nathan Drake user.firstName = 'Francis' console.log(user.fullName) // Francis Drake user.age = '29' console.log(user.age) // 29 // user.age = 'invalid text' // Error: Age has to be a number 

Getter und Setter sind keine ES5-Standardinnovationen. Sie waren immer in der Sprache präsent. In ES5 wurden nur praktische Syntaxwerkzeuge hinzugefügt, um mit ihnen zu arbeiten. Details zu Gettern und Setzern finden Sie hier .

Beispiele für die Verwendung von Gettern sind die beliebte Node.js Colors- Bibliothek.

Diese Bibliothek erweitert die String-Klasse und fügt ihr viele Getter-Methoden hinzu. Auf diese Weise können Sie eine Zeichenfolge in ihre "farbige" Version konvertieren, sodass diese Zeichenfolge dann für die Protokollierung verwendet werden kann. Dies erfolgt durch Arbeiten mit Zeichenfolgeneigenschaften.

Komma-Operator


JS hat einen Kommaoperator. Sie können mehrere Ausdrücke in eine einzelne Zeile schreiben, die durch ein Komma getrennt sind, und das Ergebnis der Auswertung des letzten Ausdrucks zurückgeben. So sehen solche Designs aus.

 let result = expression1, expression2,... expressionN 

Hier werden die Werte aller Ausdrücke berechnet, wonach der Wert von expressionN in die result gelangt.

Möglicherweise haben Sie den Komma-Operator bereits for Schleifen verwendet.

 for (var a = 0, b = 10; a <= 10; a++, b--) 

Manchmal ist dieser Operator sehr nützlich, wenn Sie mehrere Ausdrücke in dieselbe Zeile schreiben müssen.

 function getNextValue() {   return counter++, console.log(counter), counter } 

Dies kann beim Entwerfen kleiner Pfeilfunktionen hilfreich sein.

 const getSquare = x => (console.log (x), x * x) 

Plus-Betreiber


Wenn Sie eine Zeichenfolge schnell in eine Zahl umwandeln müssen, ist der Plus-Operator hilfreich für Sie. Er kann mit einer Vielzahl von Zahlen arbeiten, und nicht nur, wie es scheint, mit positiven. Wir sprechen von negativen, oktalen, hexadezimalen Zahlen und Zahlen in Exponentialschreibweise. Darüber hinaus können Datumsobjekte und Moment.js-Bibliotheksobjekte in Zeitstempel konvertiert werden.

 //  "" +'9.11'          // 9.11 +'-4'            // -4 +'0xFF'          // 255 +true            // 1 +'123e-5'        // 0.00123 +false           // 0 +null            // 0 +'Infinity'      // Infinity +'1,234'         // NaN +new Date      // 1542975502981 ( ) +momentObject    // 1542975502981 ( ) 

Doppeltes Ausrufezeichen


Es sollte beachtet werden, dass das, was manchmal als "doppelter Ausrufezeichenoperator" (Bang Bang oder Double Bang) bezeichnet wird, tatsächlich kein Operator ist. Dies ist ein logischer NOT-Operator oder ein logischer Negationsoperator, der wie ein Ausrufezeichen aussieht, das zweimal wiederholt wird. Das doppelte Ausrufezeichen ist gut, da Sie damit jeden Ausdruck in einen booleschen Wert konvertieren können. Wenn der Ausdruck aus Sicht von JS true ist, wird true zurückgegeben, nachdem er mit einem doppelten Ausrufezeichen verarbeitet wurde. Andernfalls wird false zurückgegeben.

 //     !!null            // false !!undefined       // false !!false           // false !!true            // true !!""              // false !!"string"        // true !!0               // false !!1               // true !!{}              // true !![]              // true 

Bitweiser Negationsoperator


Seien wir ehrlich: Niemand kümmert sich um bitweise Operatoren. Ich spreche nicht davon, sie zu benutzen. Der bitweise Negationsoperator kann jedoch in vielen Situationen verwendet werden.

Wenn dieser Operator auf Zahlen angewendet wird, konvertiert er sie wie folgt: Aus der Zahl N ergibt sich -(N+1) . Ein solcher Ausdruck ergibt 0 wenn N -1 .

Diese Funktion kann mit der indexOf() -Methode verwendet werden, wenn die Existenz eines Elements in einem Array oder einer Zeichenfolge überprüft wird, da diese Methode -1 zurückgibt, wenn das Element nicht gefunden wird.

 //      indexOf let username = "Nathan Drake" if (~username.indexOf("Drake")) { console.log('Access denied') } else { console.log('Access granted') } 

Es ist zu beachten, dass in den ES6- bzw. ES7-Standards für Strings und Arrays die Methode include includes() wurde. Es ist definitiv viel bequemer, das Vorhandensein von Elementen zu bestimmen, als den bitweisen Negationsoperator und indexOf() .

Benannte Blöcke


JavaScript hat ein Konzept von Beschriftungen, mit denen Sie Schleifen Namen (Beschriftungen) zuweisen können. Sie können diese Beschriftungen dann verwenden, um auf die entsprechende Schleife zu verweisen, wenn Sie break- oder continue Anweisungen anwenden. Beschriftungen können auch regulären Codeblöcken zugewiesen werden.

Beschriftete Schleifen sind nützlich, wenn Sie mit verschachtelten Schleifen arbeiten. Sie können aber auch verwendet werden, um Code bequem in Blöcken zu organisieren oder um Blöcke zu erstellen, in denen Code unterbrochen werden kann.

 //    declarationBlock: { //       //     var i, j } forLoop1: //     - "forLoop1" for (i = 0; i < 3; i++) {       forLoop2: //     -  "forLoop2"  for (j = 0; j < 3; j++) {       if (i === 1 && j === 1) {        continue forLoop1     }     console.log('i = ' + i + ', j = ' + j)  } } /* i = 0, j = 0 i = 0, j = 1 i = 0, j = 2 i = 1, j = 0 i = 2, j = 0 i = 2, j = 1 i = 2, j = 2 */ //      loopBlock4: { console.log('I will print') break loopBlock4 console.log('I will not print') } // I will print 

Beachten Sie, dass es in JS im Gegensatz zu einigen anderen Sprachen keine goto . Daher werden Beschriftungen nur mit break und continue Anweisungen verwendet.

Zusammenfassung


In diesem Artikel haben wir über wenig bekannte JavaScript-Funktionen gesprochen, deren Kenntnis für jeden JS-Programmierer nützlich ist, zumindest um bereit zu sein, etwas Ungewöhnliches im Code eines anderen zu treffen. Wenn das Thema „Unbekannter JS“ für Sie interessant ist, können Sie sich unsere Veröffentlichung ansehen.

Liebe Leser! Wenn Sie einige wenig bekannte Funktionen von JS kennen und Optionen für deren praktische Anwendung sehen, teilen Sie uns diese bitte mit.

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


All Articles