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
- Pfeilfunktionen Einzeiler haben, die das tun, und
- Ich mochte die geschweiften Klammern in den Template-Literalen oben nicht
Der Grund, warum ich das mag, ist, dass
- etwas Kapselung Klarheit schaffen kann, besonders bei Logik, und
- 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.
Interessant. Was ich mir wünschen würde: Array.prototype.last, weil ich [list.length-1] nicht mag.
Gute Nachrichten! Es gibt einen Vorschlag der Stufe 1 dafür https://github.com/keithamus/proposal-array-last
Schön, danke für den Link, Simeon!
OMG. Vielen Dank. Ich lerne gerade, JS zu
verstehen. ^^Ich mag den Ansatz, aber ich bin mir nicht sicher, ob ich die spezifischen Ideen tatsächlich mag. Der ganze Sinn dieser Übung ist es, die Diskussion anzuregen, richtig? Hier sind also meine Gedanken :)
Die Verwendung eines Pipezeichens im ternären Operator ist interessant, aber sie kollidiert mit der bestehenden Syntax. Dieser Ansatz geht meiner Meinung nach nicht weit genug. Besser wäre es, eine Sprachfunktion (vielleicht Pattern Matching?) hinzuzufügen, die eine sauberere if-elseif-Syntax für Ausdrücke bietet.
const foo = (x) => { ... }sperrig ist, aber ich hätte Angst, dassfoo(x) { ... }nicht klar macht, was passiert. Das ist aber eine geringfügige Beschwerde, mir gefällt das meiste davon, nur so am Rande.Danke für das Schreiben dieses Artikels, definitiv eine lustige Gedankenübung!
Meiner Meinung nach wäre die implizite Rückgabe eine positive Gesamtänderung, aber wir müssten sie mit einer besseren Ergonomie für die Rückgabe von
undefinedkoppeln, wie bei einer Standardfunktion ohne Rückgabe.Was wäre, wenn wir sie mit einer weiteren Syntaxänderung koppeln würden? Da JS Semikolons (;) als Anweisungsbegrenzer verwendet, was wäre, wenn der Interpreter eine
undefined-Anweisung zwischen aufeinanderfolgende Semikolons einfügen würde? Zum Beispiel würde;;interpretiert als;undefined;Zum Beispiel eine Standardfunktion
Könnte in Sarahs vorgeschlagener Syntax geschrieben werden als
Ich stimme zu, dass Template-Literale ERSTAUNLICH sind, aber darüber hinaus stimme ich dem meisten nicht zu. Die implizite Rückgabe zum Beispiel... du willst die Notwendigkeit des Wortes
returneliminieren. Aber *verlangen* es, wenn du einevoid-Funktion willst? Das verschiebt nur das "Problem".Willkommen bei CoffeeScript!
Eine Sache, die mich an CoffeeScript immer gestört hat, ist die umständliche Art, eine Funktion als void zu deklarieren
Ersetze
console.logdurch etwas, das einen Wert zurückgibt.Hmm, ich habe JS-Vorlagen nie wirklich vermisst (habe sie immer in nicht ausgeführten Skript-Tags aufbewahrt). Das Vermischen von Technologien innerhalb von Komponenten ist ziemlich modern, aber es ist nicht der einzige Weg, um sauberen und überschaubaren Code zu erzeugen.
Dieses Beispiel zeigt, wie man eine Vorlage vom JS-Code trennt (jQuery-Stil). Einfach in fast jedem CMS einzubetten. Leicht zu warten mit svn, git etc.
Es ist *sehr* einfach, eigene Abstraktionen auf diesem Muster aufzubauen, ohne Dutzende (Vue, React) oder Hunderte (Angular) neuer Semantiken zu implementieren.
Es klingt, als wärst du bereit für funktionale Programmierung! Probiere eine Sprache aus, die auf ML basiert. Du wirst feststellen, dass vieles von dem, was du suchst, dort verborgen ist. Angesichts deiner Liebe zu JS ist Elm vielleicht der einfache Weg vorwärts... Wenn nicht, dann vielleicht F# (ein persönlicher Favorit) oder Haskell (wenn du dich traust!).
Du gehst davon aus, dass ich nicht schon mit Elm etc. herumgespielt habe ;)
Wenn dein Ternary so kompliziert ist, wäre dann nicht die normale if-Syntax viel sauberer als dieses neue vorgeschlagene Ternary?
Ja, ich bin bei dir. Ich schreibe nicht den einzigen Code, den ich pflege, und viele Leute schreiben Ternaries in letzter Zeit so.
Das ist einer der Gründe, warum Ternarys an sich schon eine schlechte Idee sind.
Wenn du wirklich eine if/else schreiben willst, dann tu es einfach!
Ich persönlich würde das hier schreiben
als
Ja, das wäre wahrscheinlich besser gewesen.
Die impliziten Rückgaben von CoffeeScript waren meiner Erfahrung nach die Ursache für viele schwer zu findende Fehler. In einer Sprache mit so vielen Nebeneffekten, die nicht streng funktional ist, denke ich wirklich, dass es am besten ist, explizit zu sein, was wir zurückgeben wollen.
Interessant. Sieht so aus, als würdest du dein eigenes CoffeeScript kreieren :)
Ich liebe einige deiner Ideen, besonders implizite Rückgaben. Ich habe mit Sprachen mit impliziten Rückgaben gearbeitet und es ist wirklich schön. Ich hatte nie die Notwendigkeit, explizit
undefinedzurückzugeben. Es ergibt einfach Sinn, genau wie das, was wir mitdo expressionsbekommen werden.Um verschachtelte bedingte Ausdrücke zu bekämpfen (die ich sowieso vermeide), würde ich eher etwas wie Pattern Matching in Funktionssignaturen und Funktionsüberladungen sehen. Anstatt also dieses
Bekommst du
Natürlich scheint das Schlüsselwort
constbei der Überladung nicht richtig zu sein, aber du verstehst, worum es geht :DÜbrigens könnten wir Pattern Matching bekommen, nur nicht in Funktionssignaturen... aber es ist immer noch viel besser als verschachtelte bedingte Ausdrücke. Derzeit nur Stufe 0.
JA! High Fives
Wie wäre es mit automatischem Currying wie diesem
Damit curried sich wie
Ganz wie Ramda.curry
Ich liebe Curry(ing)
Ich liebe es, Herr Curry
Ich mag deine Ideen zur Vereinfachung der Sprache, ein sehr inspirierender Beitrag! Wenn ich darüber nachdenke, würde ich auch gerne die Schlüsselwörter
let,constundvarbeim Deklarieren einer Variablen überspringen können (wie Python).Beispiel: Wenn du
x = 1tippst, wird es als eine Variable im Geltungsbereich behandelt, genau wie bei der Verwendung vonletheute. Wenn du das heute tust, wird die Variable meiner Meinung nach als global behandelt (var) und jeder Linter und jede IDE der Welt würde wahrscheinlich verrückt werden.Das ist genau die Art von Vereinfachung, die ich gutheißen kann.
Leider kann die Ternary-Operation kein Pipe-Zeichen anstelle eines Doppelpunkts verwenden, da das einzelne Pipe-Zeichen bereits ein „bitwise or“-Operator ist.
(Objektorientierte) Entwurfsmuster für wiederkehrende Probleme.
In Beschreibungs- oder Vorlageformat (nicht statische „fertige“ Copy-Paste-Schnipsel), damit jedes Muster auf die Lösung des Problems für eine bestimmte Situation oder eine bestimmte Umgebung zugeschnitten werden kann.
Ich mag die Idee der vereinfachten Funktionsformatierung, sie würde es auch viel einfacher machen, Code in/aus Klassen zu refaktorieren usw. Der einzige Teil, der mir daran nicht gefällt, ist das Entfernen der Pfeilsyntax für Einzeiler.
Die aktuelle Syntax ist in dieser Anwendung einfacher zu lesen. ABER, vielleicht wäre es schön, wenn die Pfeilsyntax NUR mit einzeiligen Ausdrücken funktionieren würde, die die Werte automatisch zurückgeben.
Das würde uns erlauben, Dinge wie die folgenden zu tun
https://gist.github.com/AnastasiaDunbar/b87aa100af309c3eba23a27f7ae0d617
Template Literals
Ich möchte
${}anstelle von[]weiter verwenden, weil es mühsam wäre, die Zeichen zu escapen, und auch Ruby verwendet#{}, was dem JavaScript ähnlich ist. Ich denke, die Verwendung von zwei Zeichen, um eine Zeichenfolgeninterpolation zu beginnen, fühlt sich besser an, auch wenn du das Dollarzeichen vielleicht hasst.Ternäre Operatoren
Es wäre für Neulinge, die C-Sprachen verwendet haben, verwirrend,
|anstelle von:für den ternären Operator zu verwenden, und ich sehe darin keinen Vorteil.Pfeilfunktionen
Hier gibt es ein Problem, das die lokale Gültigkeit betrifft
Toller Artikel, ich liebe die Analyse, wohin sich die JS-Syntax entwickeln könnte.
Pfeilfunktionen machen den Code vielleicht einfacher zu schreiben, aber sie sind verwirrend zu lesen. Immer wenn ich => sehe, denke ich an =. Es sollte ein anderes Symbol sein, eines, das nicht als Operator verwendet wird.