ES6-Vorlagenliterale gegen verkettete Zeichenfolgen

86

Ich habe den folgenden Code für Ecma-Script-6 template literals

let person = {name: 'John Smith'};   
let tpl = `My name is ${person.name}.`;    
let MyVar="My name is "+ person.name+".";

console.log("template literal= "+tpl);  
console.log("my variable = "+MyVar);

Die Ausgabe ist wie folgt:

template literal= My name is John Smith.
my variable = My name is John Smith.

Das ist die Geige. Ich habe versucht, nach dem genauen Unterschied zu suchen, konnte ihn aber nicht finden. Meine Frage ist, was der Unterschied zwischen diesen beiden Aussagen ist.

  let tpl = `My name is ${person.name}.`;    

Und

  let MyVar = "My name is "+ person.name+".";

Ich kann die Zeichenfolge hier bereits MyVarverketten. In person.namewelchem ​​Szenario sollte das Vorlagenliteral verwendet werden?

Naeem Shaikh
quelle
8
Dies ist ein allgemeines Merkmal in anderen Sprachen, über die Zeit! Sieht sauberer aus und ist mehrzeilig.
Elclanrs
5
Nicht sicher, was du mit "Unterschied" meinst tpl === MyVar? Der einzige Unterschied ist die Syntax, mit der sie erstellt wurden. Beachten Sie, dass Vorlagen im Gegensatz zur Verkettung von Zeichenfolgen auch Tag-Funktionen bereitstellen, die beispielsweise für die automatische Escape-Funktion verwendet werden können.
Bergi
Sie fragen sich im Grunde, was der Unterschied zwischen String-Interpolation und String-Verkettung ist.
Damjan Pavlica

Antworten:

107

Wenn Sie Vorlagenliterale nur mit Platzhaltern (z. B. `Hello ${person.name}`) wie im Beispiel der Frage verwenden, entspricht das Ergebnis dem Verketten von Zeichenfolgen. Subjektiv sieht es besser aus und ist leichter zu lesen, insbesondere bei mehrzeiligen Zeichenfolgen oder Zeichenfolgen, die beide enthalten, 'und "da Sie diesen Zeichen nicht mehr entkommen müssen.

Die Lesbarkeit ist eine großartige Funktion, aber das Interessanteste an Vorlagen sind getaggte Vorlagenliterale :

let person = {name: 'John Smith'}; 
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];  
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!

In der dritten Zeile dieses Beispiels wird eine Funktion mit dem Namen tagaufgerufen. Der Inhalt der Vorlagenzeichenfolge ist in mehrere Variablen unterteilt, auf die Sie in den Argumenten der tagFunktion zugreifen können : Literalabschnitte (in diesem Beispiel der Wert von strArr[0]is My name is und der Wert von strArr[1]is !) und Substitutionen ( John Smith). Das Vorlagenliteral wird nach dem ausgewertet, was die tagFunktion zurückgibt.

Das ECMAScript-Wiki listet einige mögliche Anwendungsfälle auf, z. B. das automatische Escape- oder Codieren von Eingaben oder die Lokalisierung. Sie können eine Tag-Funktion mit dem Namen erstellen msg, die die wörtlichen Teile nachschlägt My name is und sie durch Übersetzungen in die Sprache des aktuellen Gebietsschemas ersetzt, z. B. ins Deutsche:

console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.

Der von der Tag-Funktion zurückgegebene Wert muss nicht einmal eine Zeichenfolge sein. Sie können eine Tag-Funktion mit dem Namen erstellen, $die die Zeichenfolge auswertet und als Abfrageselektor verwendet, um eine Sammlung von DOM-Knoten zurückzugeben, wie in diesem Beispiel :

$`a.${className}[href=~'//${domain}/']`
Kapex
quelle
2
Nett! Wenn Sie dort ein anderes Vorlagenliteral hätten, wie $ {person.message}, würde es mitübersetzt werden?
Rigotti
1
@ Rigotti Das liegt an der Implementierung der msgFunktion. Sie könnten sicherlich auch die Substitutionswerte übersetzen.
Kapex
@Beat Die gesamte ecmascript.org-Site scheint ausgefallen zu sein. Ich denke, sie hatten sowieso Pläne, ihr Wiki aufzugeben, deshalb habe ich die Links mit archivierten Versionen aktualisiert.
Kapex
Ich versuche $ zu laufen a.${className}[href=~'//${domain}/']in Chromkonsole (und setzte vor className=''und domain=''aber ich habe nicht den DOM - Knoten aber Array von Strings: / (in der anderen hadn, in jsfiddle wir Fehler in der Konsole erhalten: jsfiddle.net/d1fkta76 „Uncaught Reference : $ ist nicht definiert "- warum?
Kamil Kiełczewski
2
@AniketSuryavanshi Hier ist ein Vergleich der Vorlagenzeichenfolgen mit der Verkettungsleistung: stackoverflow.com/a/29083467/897024 Vor einigen Jahren waren Vorlagenzeichenfolgen langsamer, aber es sieht so aus, als wären sie etwas schneller als die Verkettung.
Kapex
17

ES6Es wird eine neue Art von Zeichenfolgenliteral entwickelt, bei der das `Back-Tick als Trennzeichen verwendet wird. Mit diesen Literalen können grundlegende Zeichenfolgeninterpolationsausdrücke eingebettet werden, die dann automatisch analysiert und ausgewertet werden.

let actor = {name: 'RajiniKanth', age: 68};

let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
  "<p>I am " + actor.age + " old</p>\n";

let newWayHtmlStr =
 `<p>My name is ${actor.name},</p>
  <p>I am ${actor.age} old</p>`;

console.log(oldWayStr);
console.log(newWayHtmlStr);

Wie Sie sehen können, haben wir das ..`` um eine Reihe von Zeichen verwendet, die als Zeichenfolgenliteral interpretiert werden. Alle Ausdrücke des Formulars ${..}werden jedoch sofort analysiert und inline ausgewertet.

Ein wirklich schöner Vorteil interpolierter String-Literale ist, dass sie sich über mehrere Zeilen verteilen dürfen:

var Actor = {"name" : "RajiniKanth"};

var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!

Interpolierte Ausdrücke

Jeder gültige Ausdruck darf ${..}in einer interpolierten Zeichenfolge enthalten sein lit‐ eral, einschließlich Funktionsaufrufen, Inline-Funktionsausdrucksaufrufen und sogar anderen interpo‐ lated string literals!

function upper(s) {
 return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!

Hier war das innere interpolierte $ {who} s``-String-Literal für uns ein wenig angenehmer, wenn wir die who-Variable mit dem "s"String kombinierten , im Gegensatz zu who + "s". Um eine Notiz zu behalten, ist ein interpoliertes String-Literal genau dort, lexically scopedwo es erscheint, dynamically scopedin keiner Weise

function foo(str) {
 var name = "foo";
 console.log( str );
}
function bar() {
 var name = "bar";
 foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"

Die Verwendung des template literalfür den HTML-Code ist definitiv besser lesbar, da der Ärger verringert wird.

Der einfache alte Weg:

'<div class="' + className + '">' +
  '<p>' + content + '</p>' +
  '<a href="' + link + '">Let\'s go</a>'
'</div>';

Mit ES6:

`<div class="${className}">
  <p>${content}</p>
  <a href="${link}">Let's go</a>
</div>`
  • Ihre Zeichenfolge kann mehrere Zeilen umfassen.
  • Sie müssen Anführungszeichen nicht umgehen.
  • Sie können Gruppierungen wie: '">' vermeiden.
  • Sie müssen den Plus-Operator nicht verwenden.

Verschlagwortet mit Vorlagenliterale

Wir können auch eine templateZeichenfolge markieren . Wenn eine templateZeichenfolge markiert wird, werden die literalsErsetzungen und an die Funktion übergeben, die den resultierenden Wert zurückgibt.

function myTaggedLiteral(strings) {
  console.log(strings);
}

myTaggedLiteral`test`; //["test"]

function myTaggedLiteral(strings,value,value2) {
  console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5

Wir können den spreadOperator hier verwenden, um mehrere Werte zu übergeben. Das erste Argument - wir haben es Strings genannt - ist ein Array aller einfachen Strings (das Zeug zwischen interpolierten Ausdrücken).

Wir sammeln dann alle nachfolgenden Argumente in einem Array namens values ​​mit dem ... gather/rest operator, obwohl Sie sie natürlich als einzelne benannte Parameter belassen könnten, die dem string-Parameter folgen, wie wir es oben getan haben (value1, value2 etc).

function myTaggedLiteral(strings,...values) {
  console.log(strings);
  console.log(values);    
}

let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]

Das argument(s)in unserem Wertearray gesammelte Ergebnis sind die Ergebnisse der bereits ausgewerteten Interpolationsausdrücke, die im Zeichenfolgenliteral enthalten sind. A tagged string literalist wie ein Verarbeitungsschritt, nachdem die Interpolationen ausgewertet wurden, aber bevor der endgültige Zeichenfolgenwert kompiliert wurde, sodass Sie mehr Kontrolle über das Generieren der Zeichenfolge aus dem Literal haben. Schauen wir uns ein Beispiel für die Erstellung eines re-usable templates.

const Actor = {
  name: "RajiniKanth",
  store: "Landmark"
}

const ActorTemplate = templater`<article>
  <h3>${'name'} is a Actor</h3>
  <p>You can find his movies at ${'store'}.</p>

</article>`;

function templater(strings, ...keys) {
  return function(data) {
  let temp = strings.slice();
  keys.forEach((key, i) => {
  temp[i] = temp[i] + data[key];
  });
  return temp.join('');
  }
};

const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);

Rohe Saiten

Unsere Tag-Funktionen erhalten ein erstes Argument, das wir aufgerufen stringshaben array. Es sind jedoch noch einige weitere Daten enthalten: die unverarbeiteten Rohversionen aller Zeichenfolgen. Sie können mit der .rawEigenschaft wie folgt auf diese unformatierten Zeichenfolgenwerte zugreifen :

function showraw(strings, ...values) {
 console.log( strings );
 console.log( strings.raw );
}
showraw`Hello\nWorld`;

Wie Sie sehen können, rawbehält die Version der Zeichenfolge die maskierte \ n-Sequenz bei, während die verarbeitete Version der Zeichenfolge sie wie eine echte neue Zeile behandelt. ES6kommt mit einer eingebauten Funktion, die als String-Literal-Tag verwendet werden kann : String.raw(..). Es geht einfach durch die Rohversionen von strings:

console.log( `Hello\nWorld` );
/* "Hello
World" */

console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"
Thalaivar
quelle
4

Es ist viel sauberer und, wie in den Kommentaren angegeben, in anderen Sprachen üblich. Das andere, was ich nett fand, waren die Zeilenumbrüche, die beim Schreiben von Strings sehr nützlich waren.

let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };

let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
                   "<p>I am " + person.age + " old</p>\n" +
                   "<strong>\"" + person.greeting +"\" is what I usually say</strong>";


let newHtmlStr = 
 `<p>My name is ${person.name},</p>
  <p>I am ${person.age} old</p>
  <p>"${person.greeting}" is what I usually say</strong>`;


console.log(usualHtmlStr);
console.log(newHtmlStr);
Rigotti
quelle
Ich verstehe nicht, ob es einen großen Unterschied zwischen Zeilenumbrüchen in einem String und einem Literal gibt. Überprüfen Sie dies es6fiddle.net/i3vj1ldl . Literal setzt nur ein Leerzeichen anstelle eines Zeilenumbruchs
Naeem Shaikh
1
Woh, ich habe nicht gesagt, dass es ein großer Unterschied ist. Literale Zeilenumbrüche sind nur Syntaxzucker. Es ist nur der Lesbarkeit halber.
Rigotti
Trotzdem haben Sie auf einen guten Unterschied hingewiesen. Aber bevor ich Ihre Antwort akzeptiere, werde ich noch einige Zeit auf eine bessere Antwort warten, die einen großen Unterschied zeigt (falls es welche gibt!) :)
Naeem Shaikh
2
@NaeemShaikh Es tut mir schrecklich leid, aber wörtliche Zeilenumbrüche funktionieren tatsächlich. Ich habe gerade bemerkt, dass ES6Fiddle nur eine schreckliche Möglichkeit ist, es zu testen. Ich werde meine Antwort bearbeiten.
Rigotti
2

Während meine Antwort die Frage nicht direkt anspricht. Ich dachte, es könnte von Interesse sein, auf einen Nachteil der Verwendung von Vorlagenliteralen zugunsten des Array-Joins hinzuweisen.

Sagen wir, ich habe

let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};

Einige Patienten haben also einen zweiten Vornamen, andere nicht.

Wenn ich eine Zeichenfolge wollte, die den vollständigen Namen eines Patienten darstellt

let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;

Dann würde dies "John undefined Smith" werden

Aber wenn ich es tat

let patientName = [patient1.firstName, patient1.middleName,  patient1.lastName].join(" ");

Dann würde dies nur "John Smith" werden

BEARBEITEN

General_Twyckenham wies darauf hin, dass ein Join auf "" zu einem zusätzlichen Leerzeichen zwischen "John" und "Smith" führen würde.

Um dies zu umgehen, können Sie vor dem Join einen Filter verwenden, um falsche Werte zu entfernen: [patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");

Dhruv Prakash
quelle
2
Eigentlich ist das nicht ganz richtig - die joinVersion gibt Ihnen John Smith mit einem zusätzlichen Platz. Wie Sie sich vorstellen können, ist dies oft unerwünscht. Ein Fix dafür ist mapwie folgt zu verwenden :[patient1.firstName, patient1.middleName, patient1.lastName].map(el => el).join(" ");
General_Twyckenham
@ General_Twyckenham aah Ich verstehe deinen Standpunkt. Guter Fang. Außerdem sollte es ein Filter und keine Karte sein, um diesen zusätzlichen Speicherplatz zu entfernen. Ich werde meine Antwort bearbeiten, danke.
Dhruv Prakash
Whoops - ja, filterwar die Funktion, die ich meinte.
General_Twyckenham
Und gemäß dieser Diskussion ist die Verkettung von Zeichenfolgen schneller als die Verknüpfung von Arrays. stackoverflow.com/questions/7299010/…
Michael Harley