JavaScript, ich liebe dich, du bist perfekt, jetzt ändere dich

Avatar of Sarah Drasner
Sarah Drasner am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Diejenigen von uns, die Weihnachten oder Hannukkah feiern, haben wahrscheinlich starke Erinnerungen an die Aufregung im Dezember. Erinnerst du dich an die Monate vor Weihnachten, als deine Fantasie mit Ideen explodierte, Antworten auf die große Frage: „Was wünschst du dir zu Weihnachten?“ Als Kind, weil du nicht von erwachsenen Verpflichtungen und sogar von den Grenzen der Realität belastet wurdest, konnte die Liste von „Legosteinen“ bis „eine Reise zum Mond“ reichen (was in den kommenden Jahren wahrscheinlicher zu werden scheint).

Über eine akzeptierte Basisprämisse hinauszudenken – die Grenzen dessen, was wir über etwas wissen –, kann eine nützliche mentale Übung sein. Ich liebe zum Beispiel JavaScript, aber was wäre, wenn ich, wie Weihnachten als Kind, einfach entscheiden könnte, was es sein könnte? Es gibt kleine Anpassungen an der Syntax, die mein Leben nicht verändern würden, es aber nur ein kleines bisschen besser machen würden. Schauen wir uns das mal an.

Wie mein Kollege und Freund Brian Holt sagt,

Holt eure Pinsel raus! Heute werden wir Bikeshedding betreiben!

Template-Literale

Zuerst einmal muss ich sagen, dass Template-Literale wahrscheinlich mein Lieblingsteil von ES6 waren. Als jemand, der regelmäßig SVG-Pfadzeichenfolgen manipuliert, hat der Wechsel von Zeichenfolgenverkettung zu Template-Literalen buchstäblich mein verdammtes Leben verändert. Schauen Sie sich die Rückgabe dieser Funktion an

function newWobble(rate, startX) {
  ...
  
  if (i % 2 === 0) {
    pathArr2[i] = pathArr2[i] + " Q " + in1 + " " + QRate;
  } else {
    pathArr2[i] = pathArr2[i] + " Q " + in2 + " " + QRate;
  }

  ...
  return "M" + pathArr2.join("") + " " + startX + " " + (inc * (rate*2) + rate);
}

Wird zu

const newWobble = (rate, startX) => {
  ...
  
  if (i % 2 === 0) {
    pathArr2[i] = `${pathArr2[i]} Q ${in1} ${QRate}`;
  } else {
    pathArr2[i] = `${pathArr2[i]} Q ${in2} ${QRate}`;
  }

  ...
  return `M${pathArr2.join("")} ${startX} ${(inc * (rate*2) + rate)}`;
}

...was viel einfacher zu lesen und zu bearbeiten ist. Aber könnte das verbessert werden? Natürlich kann es das!

Das Parsen von ${x} erfordert eine kleine kognitive Last, hauptsächlich aufgrund der Art der Zeichen selbst. Was wäre also, wenn Template-Literale das Dollarzeichen verlieren und stattdessen eckige Klammern verwenden würden? Anstatt

return `M${pathArr2.join("")} ${startX} ${(inc * (rate*2) + rate)}`

...können wir so etwas haben wie

return `M[pathArr2.join("")] [startX] [(inc * (rate*2) + rate)]`

...was viel stromlinienförmiger ist.

Ternäre Operatoren

Ternäre Operatoren sind interessant, denn in den letzten Jahren haben sie sich nicht verändert, aber *wir* haben uns verändert. Viel modernes JavaScript macht intensiven Gebrauch von Ternaries, was mich dazu bringt, ihre aktuelle Syntax wieder zu überdenken.

Zum Beispiel eine Einzeiler-Zeile wie

const func = function( .. ) {
  return condition1 ? value1 : value2
}

...ist nicht so schwer zu lesen und zu verstehen. Aber hier ist, was ich in letzter Zeit viel gelesen habe

const func = function( .. ) {
  return condition1 ? value1
       : condition2 ? value2
       : condition3 ? value3
       :              value4
}

Dies ist viel schwerer zu lesen, hauptsächlich weil der Doppelpunkt : je nach Code-Editor und Syntax-Highlighting-Einstellungen verloren geht. Und was ist, wenn jemand diesen Code nicht richtig formatiert? Er kann leicht werden

const func = function( .. ) {
  return condition1 ? value1 : condition2 ? value2 : condition3 ? value3 : value4
}

...in diesem Fall sind die Doppelpunkte auf den ersten Blick extrem schwer zu erkennen. Was wäre also, wenn wir einen visuellen Indikator verwenden würden, der etwas stärker ist?

const func = function( .. ) {
  return condition1 ? value1 | condition2 ? value2 | condition3 ? value3 | value4
}

Ein Pipezeichen unterbricht den Fluss nicht, trennt aber dennoch auf eine Weise, die nicht so leicht zu übersehen ist.

Pfeilfunktionen

Ich werde mich damit unbeliebt machen, weil es jedermanns Liebling ist, aber Pfeilfunktionen waren für mich immer ein Fehlschlag. Nicht, weil sie nicht nützlich sind – ganz im Gegenteil. Pfeilfunktionen sind wunderbar! Aber es gab immer etwas an der Lesbarkeit dieses dicken Pfeils, das mich störte. Ich bin jetzt daran gewöhnt, aber es hat mich beunruhigt, dass es mich, als ich sie zum ersten Mal lernte, ein oder zwei zusätzliche Sekunden gekostet hat, sie zu lesen. Das ging schließlich vorbei, aber tun wir mal so, als könnten wir unseren Kuchen haben und ihn auch essen.

Ich schlage definitiv nicht vor, dass wir immer noch das Wort function verwenden. Tatsächlich würde ich es lieben, wenn Pfeilfunktionen nicht von Natur aus anonym wären, denn

const foo = (y) => { 
  const x
  return x + y
}

...ist nicht ganz so elegant wie

const foo(y) => {
  const x
  return x + y
}

In meiner perfekten Welt würden wir die Funktion und den Pfeil weglassen, damit wir etwas hätten, das mehr einem Methodenaufruf ähnelt

foo(y) {
  const x
  return x + y
}

und eine anonyme Funktion könnte einfach sein

(y) {
  const x
  return x + y
}

Oder sogar ein Einzeiler

(y) { y += 1 }

Ich weiß, viele Leute werden darauf hinweisen, dass

  1. Pfeilfunktionen Einzeiler haben, die das tun, und
  2. Ich mochte die geschweiften Klammern in den Template-Literalen oben nicht

Der Grund, warum ich das mag, ist, dass

  1. etwas Kapselung Klarheit schaffen kann, besonders bei Logik, und
  2. geschweifte Klammern sind ein stärkeres visuelles Signal, weil sie mehr visueller Lärm sind. Funktionen sind wichtig genug, um diese Art von High-Level-Visualluxus zu benötigen, während Template-Literale das nicht sind.

Okay, gehen wir jetzt noch einen Schritt weiter. Was wäre, wenn wir immer eine implizite Rückgabe in der letzten Zeile hätten? Dann könnten wir jetzt

foo(y) {
  const x
  x + y
}

Oder…

(y) {
  const x
  x + y
}

Wenn wir nicht zurückgeben wollten, könnten wir immer noch sagen

foo(y) {
  const x
  x + y
  return
}

Oder, *noch besser*, ein Sonderzeichen verwenden

foo(y) {
  const x
  x + y
  ^
}

Auf diese Weise könntest du, wann immer du statt der letzten Zeile eine andere Zeile zurückgeben möchtest, return verwenden und es würde wie gewohnt funktionieren

foo(y) {
  const x
  return x + y
  const z
}

Was für eine Welt das sein könnte, nicht wahr?

Was nun?

Leute erfinden neue Sprachen und schreiben Compiler neu, nur um eine starke Meinung darüber zu haben, wie eine Sprache sich entwickeln oder geschrieben werden sollte. Einige meiner Lieblingsbeispiele sind Whitespace, eine Programmiersprache, die aus Tabs und Leerzeichen besteht, und Malbolge, die speziell so konzipiert wurde, dass sie unprogrammierbar ist. (Wenn Sie denken, ich sei ein Troll, weil ich diesen Artikel schreibe, dann habe ich nichts gegen den Typen, der Malbolge geschrieben hat.) Aus dem Artikel

Tatsächlich hat der Autor selbst noch nie ein einziges Malbolge-Programm geschrieben

Für diejenigen, die ernsthaft daran interessiert sind, ihre eigene Programmiersprache zu entwickeln, gibt es verfügbare Ressourcen, und es ist ziemlich interessant zu lernen.

Ich erkenne an, dass es Gründe gibt, warum JavaScript diese Änderungen nicht vornehmen kann. Dieser Artikel ist nicht als TC39-Vorschlag gedacht, sondern lediglich als Gedankenübung. Es macht Spaß, Dinge, die man für unbeweglich hält, neu zu denken, um die eigenen Annahmen über Basisprämissen zu überprüfen. Notwendigkeit mag die Mutter der Erfindung sein, aber Spiel ist ihr Vater.

Vielen Dank an Brian Holt und Kent C. Dodds, dass sie mich ertragen und diesen Artikel Korrektur gelesen haben.