Wie kann ich eine String-Interpolation in JavaScript durchführen?

535

Betrachten Sie diesen Code:

var age = 3;

console.log("I'm " + age + " years old!");

Gibt es neben der Verkettung von Zeichenfolgen noch andere Möglichkeiten, den Wert einer Variablen in eine Zeichenfolge einzufügen?

Tom Lehman
quelle
7
Sie könnten CoffeeScript auschecken
dennismonsewicz
1
Wie andere schon angedeutet haben, die Methode , die Sie verwenden , ist der einfachste Weg , um darüber zu gehen. Ich würde gerne auf Variablen in Strings verweisen können, aber in Javascript müssen Sie die Verkettung (oder einen anderen Find / Replace-Ansatz) verwenden. Leute wie Sie und ich sind wahrscheinlich ein bisschen zu sehr an PHP gebunden, als dass wir es selbst tun könnten.
Lev
4
Verwenden Sie Underscore.js Vorlage
Jahan
2
Verkettung ist keine Interpolation, und der Benutzer hat gefragt, wie die Interpolation durchgeführt werden soll. Ich denke, Lev hat endlich die Antwort gegeben, dh es gibt keine Möglichkeit, dies in nativem JS zu tun. Ich verstehe nicht, warum dies keine echte Frage ist.
Gitb
4
Wenn ich antworten darf, gibt es jetzt eine Lösung für neuere Interpreter (2015 unterstützen FF und Chrome bereits): developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Z.B. Show GRAPH of : ${fundCode}-${funcCode} holt mich Show GRAPH of : AIP001-_sma (benutze Backticks um String 1 .... kann hier nicht angezeigt werden)
Marcos

Antworten:

536

Seit ES6 können Sie Vorlagenliterale verwenden :

const age = 3
console.log(`I'm ${age} years old!`)

PS Beachten Sie die Verwendung von Backticks : ``.

Damjan Pavlica
quelle
3
Ich frage mich, warum sie diesbezüglich Backticks verwendet haben. Wäre "$ {age}" nicht genug, um Interpolation durchzuführen?
Lachende Limonade
5
@LaughingLemonade Abwärtskompatibilität. Wenn es auf diese Weise implementiert wurde, schlägt der gesamte vorhandene Code fehl, der eine Zeichenfolge in diesem Format druckt.
thefourtheye
1
@ Jonathan Ich mag Backticks immer nicht als bedeutungsvollen Charakter. Ich bin mir jedoch nicht sicher, ob der Grund universell ist oder nur für die Tastaturlayouts meiner Sprachen gilt. Backtick ist eine spezielle Art von Zeichen, die darauf wartet, bis zum nächsten Zeichen geschrieben zu werden, und das zweimal getroffen werden muss, um zu schreiben (und zu diesem Zeitpunkt zwei davon schreibt). Dies liegt daran, dass einige Zeichen mit ihnen interagieren, z. B. "e". Wenn ich versuche, mit ihnen "ello" zu schreiben, bekomme ich èllo``. Es ist auch etwas ärgerlich lokalisiert (Shift + Forwardtick, ein weiteres solches spezielles Lookahead-Zeichen), da es im Gegensatz zu 'Shift-to-Type erfordert.
Felix
@felix Es ist ein Gedanke, der spezifisch für Ihr Tastaturlayout ist. Was Sie beschreiben, heißt "tote Schlüssel". Sie sind auch im norwegischen Tastaturlayout (wo ich herkomme) vorhanden, was ein Teil des Grundes ist, warum ich für alle Programmierungen auf ein US-Tastaturlayout umsteige. (Es gibt eine Reihe anderer Zeichen - z. B. [und] -, die auch auf einer US-Tastatur viel einfacher sind.)
Eivind Eklund
239

tl; dr

Verwenden Sie gegebenenfalls die Vorlagenzeichenfolgenliterale von ECMAScript 2015.

Erläuterung

Es gibt keinen direkten Weg, dies gemäß den ECMAScript 5-Spezifikationen zu tun, aber ECMAScript 6 verfügt über Vorlagenzeichenfolgen , die bei der Erstellung der Spezifikation auch als Quasi-Literale bezeichnet wurden. Verwenden Sie sie wie folgt:

> var n = 42;
undefined
> `foo${n}bar`
'foo42bar'

Sie können einen beliebigen gültigen JavaScript-Ausdruck innerhalb von verwenden {}. Zum Beispiel:

> `foo${{name: 'Google'}.name}bar`
'fooGooglebar'
> `foo${1 + 3}bar`
'foo4bar'

Die andere wichtige Sache ist, dass Sie sich nicht mehr um mehrzeilige Zeichenfolgen kümmern müssen. Sie können sie einfach als schreiben

> `foo
...     bar`
'foo\n    bar'

Hinweis: Ich habe io.js v2.4.0 verwendet, um alle oben gezeigten Vorlagenzeichenfolgen auszuwerten. Sie können auch das neueste Chrome verwenden, um die oben gezeigten Beispiele zu testen.

Hinweis: Die ES6-Spezifikationen sind jetzt fertiggestellt , müssen jedoch noch von allen gängigen Browsern implementiert werden.
Laut den Seiten des Mozilla Developer Network wird dies für die grundlegende Unterstützung ab den folgenden Versionen implementiert: Firefox 34, Chrome 41, Internet Explorer 12. Wenn Sie ein Opera-, Safari- oder Internet Explorer-Benutzer sind und jetzt neugierig darauf sind Mit diesem Prüfstand kann herumgespielt werden, bis alle Unterstützung dafür erhalten.

thefourtheye
quelle
3
Es ist verwendbar, wenn Sie babeljs verwenden , damit Sie es in Ihre Codebasis einfügen und später den Transpilationsschritt löschen können , sobald die von Ihnen unterstützten Browser ihn implementieren.
ivarni
Gibt es eine Möglichkeit, eine Standardzeichenfolge in ein Vorlagenzeichenfolgenliteral zu konvertieren? Wenn man zum Beispiel eine JSON-Datei mit einer Übersetzungstabelle hätte, in die Werte für Anzeigezwecke interpoliert werden müssten? Ich denke, die erste Lösung funktioniert wahrscheinlich gut für diese Situation, aber ich mag die neue Syntax der Zeichenfolgenvorlage im Allgemeinen.
Nbering
Da dies immer noch eines der ersten Suchergebnisse zur js-String-Interpolation ist, wäre es großartig, wenn Sie es aktualisieren könnten, um die allgemeine Verfügbarkeit jetzt widerzuspiegeln. "Es gibt keinen direkten Weg, dies zu tun" trifft für die meisten Browser wahrscheinlich nicht mehr zu.
Felix Dombek
2
Für das schlechte Sehvermögen im Publikum ist der "Charakter anders als". Wenn Sie Probleme haben, dies zum Laufen zu bringen, stellen Sie sicher, dass Sie das Grabzitat (auch bekannt als gekipptes Zitat, hinteres Zitat) verwenden. En.wikipedia.org/wiki/Grave_accent . Es ist oben links auf Ihrer Tastatur :)
Quincy
@Quincy Unten links auf einer Mac-Tastatur - auch als Back-Tick bezeichnet :)
RB.
192

Douglas Crockfords Remedial JavaScript enthält eine String.prototype.supplantFunktion. Es ist kurz, vertraut und einfach zu bedienen:

String.prototype.supplant = function (o) {
    return this.replace(/{([^{}]*)}/g,
        function (a, b) {
            var r = o[b];
            return typeof r === 'string' || typeof r === 'number' ? r : a;
        }
    );
};

// Usage:
alert("I'm {age} years old!".supplant({ age: 29 }));
alert("The {a} says {n}, {n}, {n}!".supplant({ a: 'cow', n: 'moo' }));

Wenn Sie den Prototyp von String nicht ändern möchten, können Sie ihn jederzeit eigenständig anpassen oder in einen anderen Namespace oder was auch immer einfügen.

Chris Nielsen
quelle
102
Hinweis: Dies läuft zehnmal langsamer als nur die Verkettung.
Cllpse
36
Und nehmen Sie ungefähr dreimal mehr Tastenanschläge und Bytes.
ma11hew28
8
@roosteronacid - Können Sie eine Perspektive auf diesen Geschwindigkeitsabfall geben? Wie von 0,01s bis 0,1s (wichtig) oder von 0,000000001s bis 0,00000001s (irrelevant)?
Chris
16
@george: Ein schneller Test auf meiner Maschine ergab 7312 ns für "Die Kuh sagt moo, moo, moo!" Verwenden der Crockford-Methode vs 111 ns für eine vorkompilierte Funktion, die die Variablen aus dem übergebenen Objekt herauszieht und sie mit den konstanten Teilen der Vorlagenzeichenfolge verkettet. Dies war Chrome 21.
George
13
Oder verwenden Sie es wie:"The {0} says {1}, {1}, {1}!".supplant(['cow', 'moo'])
Robert Massa
54

Achtung: Vermeiden Sie jedes Vorlagensystem, bei dem Sie sich nicht den eigenen Trennzeichen entziehen können. Zum Beispiel gibt es keine Möglichkeit, Folgendes mit der supplant()hier erwähnten Methode auszugeben .

"Ich bin dank meiner {age} -Variable 3 Jahre alt."

Eine einfache Interpolation kann für kleine in sich geschlossene Skripte funktionieren, bringt jedoch häufig diesen Konstruktionsfehler mit sich, der jede ernsthafte Verwendung einschränkt. Ich bevorzuge ehrlich DOM-Vorlagen wie:

<div> I am <span id="age"></span> years old!</div>

Und verwenden Sie die jQuery-Manipulation: $('#age').text(3)

Wenn Sie die Verkettung von Zeichenfolgen einfach satt haben, gibt es alternativ immer eine andere Syntax:

var age = 3;
var str = ["I'm only", age, "years old"].join(" ");
greg.kindel
quelle
4
Randnotiz: Array.join()Ist langsamer als die direkte ( +Stil-) Verkettung, da Browser-Engines (einschließlich V8, einschließlich Knoten und fast alles, was JS heute
ausführt
1
Mit der Ersetzungsmethode können Sie die von Ihnen erwähnte Zeichenfolge generieren: Das {Token} wird nur ersetzt, wenn das Datenobjekt ein Element mit dem Namen aufgerufen hat. Wenn tokenSie also kein Datenobjekt mit einem Element angeben, ist agedies in Ordnung.
Chris Fewtrell
1
Chris, ich verstehe nicht, wie das eine Lösung ist. Ich könnte das Beispiel leicht aktualisieren, um sowohl eine Altersvariable als auch die Zeichenfolge {age} zu verwenden. Möchten Sie sich wirklich Gedanken darüber machen, wie Sie Ihre Variablen basierend auf dem Text der Vorlagenkopie benennen können? --Auch seit diesem Beitrag bin ich ein großer Fan von Datenbindungsbibliotheken geworden. Einige, wie RactiveJS, retten Sie vor einem DOM, das mit variablen Bereichen beladen ist. Und im Gegensatz zu Moustache wird nur dieser Teil der Seite aktualisiert.
Greg.kindel
3
Ihre primäre Antwort scheint anzunehmen, dass dieses Javascript in einer Browserumgebung ausgeführt wird, obwohl die Frage nicht mit HTML markiert ist.
Kanon
2
Ihr "Wort der Vorsicht" supplantist nicht gerechtfertigt: "I am 3 years old thanks to my {age} variable.".supplant({}));Gibt genau die angegebene Zeichenfolge zurück. Wenn agegegeben, könnte man noch drucken {und }verwenden{{age}}
le_m
23

Probieren Sie die Sprintf- Bibliothek aus (eine vollständige Open-Source-JavaScript-Sprintf-Implementierung). Zum Beispiel:

vsprintf('The first 4 letters of the english alphabet are: %s, %s, %s and %s', ['a', 'b', 'c', 'd']);

vsprintf verwendet ein Array von Argumenten und gibt eine formatierte Zeichenfolge zurück.

NawaMan
quelle
22

Ich verwende dieses Muster in vielen Sprachen, wenn ich noch nicht weiß, wie ich es richtig machen soll, und nur schnell eine Idee haben möchte:

// JavaScript
let stringValue = 'Hello, my name is {name}. You {action} my {relation}.'
    .replace(/{name}/g    ,'Indigo Montoya')
    .replace(/{action}/g  ,'killed')
    .replace(/{relation}/g,'father')
    ;

Obwohl es nicht besonders effizient ist, finde ich es lesbar. Es funktioniert immer und ist immer verfügbar:

' VBScript
dim template = "Hello, my name is {name}. You {action} my {relation}."
dim stringvalue = template
stringValue = replace(stringvalue, "{name}"    ,"Luke Skywalker")     
stringValue = replace(stringvalue, "{relation}","Father")     
stringValue = replace(stringvalue, "{action}"  ,"are")

IMMER

* COBOL
INSPECT stringvalue REPLACING FIRST '{name}'     BY 'Grendel'
INSPECT stringvalue REPLACING FIRST '{relation}' BY 'Mother'
INSPECT stringvalue REPLACING FIRST '{action}'   BY 'did unspeakable things to'
Jefferey Höhle
quelle
12

Sie können ES6 problemlos verwenden template stringund mit jedem verfügbaren Transpilar wie babel auf ES5 übertragen.

const age = 3;

console.log(`I'm ${age} years old!`);

http://www.es6fiddle.net/im3c3euc/

Mohammad Arif
quelle
6

Probieren Sie Kiwi aus , ein leichtes JavaScript-Modul für die String-Interpolation.

Du kannst tun

Kiwi.compose("I'm % years old!", [age]);

oder

Kiwi.compose("I'm %{age} years old!", {"age" : age});
zs2020
quelle
6

Wenn Sie in der console.logAusgabe interpolieren möchten , dann einfach

console.log("Eruption 1: %s", eruption1);
                         ^^

Hier %sist ein sogenannter "Formatbezeichner". console.loghat diese Art der Interpolationsunterstützung eingebaut.


quelle
1
Dies ist die einzig richtige Antwort. Bei der Frage geht es um Interpolation, nicht um Vorlagenzeichenfolgen.
Sospedra
5

Hier ist eine Lösung, bei der Sie einem Objekt die Werte bereitstellen müssen. Wenn Sie kein Objekt als Parameter angeben, werden standardmäßig globale Variablen verwendet. Aber halten Sie sich besser an den Parameter, er ist viel sauberer.

String.prototype.interpolate = function(props) {
    return this.replace(/\{(\w+)\}/g, function(match, expr) {
        return (props || window)[expr];
    });
};

// Test:

// Using the parameter (advised approach)
document.getElementById("resultA").innerText = "Eruption 1: {eruption1}".interpolate({ eruption1: 112 });

// Using the global scope
var eruption2 = 116;
document.getElementById("resultB").innerText = "Eruption 2: {eruption2}".interpolate();
<div id="resultA"></div><div id="resultB"></div>

Lucas Trzesniewski
quelle
3
Nicht benutzen eval, evalist böse!
Chris97ong
5
@ chris97ong Während das "wahr" ist, geben Sie zumindest einen Grund ("böse" hilft nicht) oder eine alternative Lösung an. Es gibt fast immer einen Weg, um zu verwenden eval, aber manchmal nicht. Wenn das OP beispielsweise eine Möglichkeit zum Interpolieren mit dem aktuellen Bereich haben möchte, ohne ein Suchobjekt übergeben zu müssen (wie die Groovy-Interpolation funktioniert), bin ich mir ziemlich sicher, evaldass dies erforderlich wäre. Greifen Sie nicht einfach auf das alte "Eval is Evil" zurück.
Ian
1
Verwenden Sie niemals eval und schlagen Sie niemals vor, es zu verwenden
hasen
2
@hasenj aus diesem Grund habe ich gesagt, dass es "möglicherweise nicht die beste Idee ist" und eine alternative Methode bereitgestellt. Leider evalist dies die einzige Möglichkeit, auf lokale Variablen im Gültigkeitsbereich zuzugreifen . Also lehne es nicht ab, nur weil es deine Gefühle verletzt. Übrigens bevorzuge ich auch den alternativen Weg, weil er sicherer ist, aber die evalMethode beantwortet genau die Frage von OP, daher ist sie in der Antwort enthalten.
Lucas Trzesniewski
1
Das Problem dabei evalist, dass nicht von einem anderen Bereich aus auf Variablen zugegriffen werden kann. Wenn sich Ihr .interpolateAufruf also in einer anderen Funktion befindet und nicht global, funktioniert er nicht.
Georg
2

Wenn Sie die zweite Antwort von Greg Kindel erweitern , können Sie eine Funktion schreiben, um einen Teil der Boilerplate zu entfernen:

var fmt = {
    join: function() {
        return Array.prototype.slice.call(arguments).join(' ');
    },
    log: function() {
        console.log(this.join(...arguments));
    }
}

Verwendungszweck:

var age = 7;
var years = 5;
var sentence = fmt.join('I am now', age, 'years old!');
fmt.log('In', years, 'years I will be', age + years, 'years old!');
James Ko
quelle
1

Ich kann Ihnen ein Beispiel zeigen:

function fullName(first, last) {
  let fullName = first + " " + last;
  return fullName;
}

function fullNameStringInterpolation(first, last) {
  let fullName = `${first} ${last}`;
  return fullName;
}

console.log('Old School: ' + fullName('Carlos', 'Gutierrez'));

console.log('New School: ' + fullNameStringInterpolation('Carlos', 'Gutierrez'));

Schatten3002
quelle
1

Wenn Sie seit ES6 eine Zeichenfolgeninterpolation in Objektschlüsseln durchführen möchten, erhalten Sie eine, SyntaxError: expected property name, got '${'wenn Sie Folgendes tun:

let age = 3
let obj = { `${age}`: 3 }

Sie sollten stattdessen Folgendes tun:

let obj = { [`${age}`]: 3 }
Yuxuan Chen
quelle
1

Weitere Informationen für die ES6- Version von @Chris Nielsens Beitrag.

String.prototype.supplant = function (o) {
  return this.replace(/\${([^\${}]*)}/g,
    (a, b) => {
      var r = o[b];
      return typeof r === 'string' || typeof r === 'number' ? r : a;
    }
  );
};

string = "How now ${color} cow? {${greeting}}, ${greeting}, moo says the ${color} cow.";

string.supplant({color: "brown", greeting: "moo"});
=> "How now brown cow? {moo}, moo, moo says the brown cow."
SoEzPz
quelle
0

Die Verwendung der Vorlagensyntax schlägt in älteren Browsern fehl. Dies ist wichtig, wenn Sie HTML für die öffentliche Verwendung erstellen. Die Verwendung der Verkettung ist langwierig und schwer zu lesen, insbesondere wenn Sie viele oder lange Ausdrücke haben oder wenn Sie Klammern verwenden müssen, um Mischungen aus Zahlen- und Zeichenfolgenelementen zu verarbeiten (beide verwenden den Operator +).

PHP erweitert Zeichenfolgen in Anführungszeichen, die Variablen und sogar einige Ausdrücke enthalten, mit einer sehr kompakten Notation: $a="the color is $color";

In JavaScript kann eine effiziente Funktion geschrieben werden, um dies zu unterstützen: var a=S('the color is ',color);unter Verwendung einer variablen Anzahl von Argumenten. In diesem Beispiel gibt es zwar keinen Vorteil gegenüber der Verkettung, aber wenn die Ausdrücke länger werden, ist diese Syntax möglicherweise klarer. Oder man kann das Dollarzeichen verwenden, um den Beginn eines Ausdrucks mithilfe einer JavaScript-Funktion wie in PHP zu signalisieren.

Andererseits wäre es nicht schwierig, eine effiziente Problemumgehungsfunktion zu schreiben, um eine vorlagenähnliche Erweiterung von Zeichenfolgen für ältere Browser bereitzustellen. Jemand hat es wahrscheinlich schon getan.

Schließlich stelle ich mir vor, dass sprintf (wie in C, C ++ und PHP) in JavaScript geschrieben werden könnte, obwohl es etwas weniger effizient wäre als diese anderen Lösungen.

David Spector
quelle
0

Benutzerdefinierte flexible Interpolation:

var sourceElm = document.querySelector('input')

// interpolation callback
const onInterpolate = s => `<mark>${s}</mark>`

// listen to "input" event
sourceElm.addEventListener('input', parseInput) 

// parse on window load
parseInput() 

// input element parser
function parseInput(){
  var html = interpolate(sourceElm.value, undefined, onInterpolate)
  sourceElm.nextElementSibling.innerHTML = html;
}

// the actual interpolation 
function interpolate(str, interpolator = ["{{", "}}"], cb){
  // split by "start" pattern
  return str.split(interpolator[0]).map((s1, i) => {
    // first item can be safely ignored
	  if( i == 0 ) return s1;
    // for each splited part, split again by "end" pattern 
    const s2 = s1.split(interpolator[1]);

    // is there's no "closing" match to this part, rebuild it
    if( s1 == s2[0]) return interpolator[0] + s2[0]
    // if this split's result as multiple items' array, it means the first item is between the patterns
    if( s2.length > 1 ){
        s2[0] = s2[0] 
          ? cb(s2[0]) // replace the array item with whatever
          : interpolator.join('') // nothing was between the interpolation pattern
    }

    return s2.join('') // merge splited array (part2)
  }).join('') // merge everything 
}
input{ 
  padding:5px; 
  width: 100%; 
  box-sizing: border-box;
  margin-bottom: 20px;
}

*{
  font: 14px Arial;
  padding:5px;
}
<input value="Everything between {{}} is {{processed}}" />
<div></div>

vsync
quelle
0

Während Vorlagen für den von Ihnen beschriebenen Fall wahrscheinlich am besten geeignet sind, können Sie sie verwenden, wenn Sie Ihre Daten und / oder Argumente in iterierbarer / Array-Form haben oder möchten String.raw.

String.raw({
  raw: ["I'm ", " years old!"]
}, 3);

Mit den Daten als Array kann man den Spread-Operator verwenden:

const args = [3, 'yesterday'];
String.raw({
  raw: ["I'm ", " years old as of ", ""]
}, ...args);
Brett Zamir
quelle
0

Konnte nicht finden, wonach ich suchte, dann fand ich es -

Wenn Sie Node.js verwenden, gibt es ein integriertes utilPaket mit einer Formatierungsfunktion, die folgendermaßen funktioniert:

util.format("Hello my name is %s", "Brent");
> Hello my name is Brent

Zufälligerweise ist dies jetzt console.logauch in Node.js in Aromen integriert -

console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
B Fisch
quelle