Jak interpolować zmienne w ciągach w JavaScript bez konkatenacji?

408

Wiem, że w PHP możemy zrobić coś takiego:

$hello = "foo";
$my_string = "I pity the $hello";

Wynik: "I pity the foo"

Zastanawiałem się, czy to samo jest również możliwe w JavaScript. Używanie zmiennych wewnątrz ciągów bez użycia konkatenacji - pisze bardziej zwięźle i elegancko.

DMin
źródło

Odpowiedzi:

695

Możesz skorzystać z literałów szablonów i użyć tej składni:

`String text ${expression}`

Literały szablonów są ujęte w tykanie (``) (poważny akcent) zamiast podwójnych lub pojedynczych cudzysłowów.

Ta funkcja została wprowadzona w ES2015 (ES6).

Przykład

var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b}.`);
// "Fifteen is 15.

Jak to jest miłe?

Premia:

Pozwala również na wieloliniowe ciągi w javascript bez zmiany znaczenia, co jest idealne dla szablonów:

return `
    <div class="${foo}">
         ...
    </div>
`;

Obsługa przeglądarki :

Ponieważ ta składnia nie jest obsługiwana przez starsze przeglądarki (głównie Internet Explorer), możesz użyć Babel / Webpack do transponowania swojego kodu do ES5, aby mieć pewność, że będzie działał wszędzie.


Dygresja:

Począwszy od IE8 +, możesz używać podstawowego formatowania ciągów wewnątrz console.log:

console.log('%s is %d.', 'Fifteen', 15);
// Fifteen is 15.
bformet
źródło
56
Nie przegap faktu, że ciąg szablonu jest ograniczony tylnymi paskami (`) zamiast zwykłych znaków cudzysłowu. "${foo}"jest dosłownie {foo} `${foo}`jest tym, czego naprawdę chcesz
Hovis Biddle
1
Ponadto istnieje wiele transpilatorów, które zamieniają ES6 w ES5, aby naprawić problem ze zgodnością!
Nick
kiedy zmieniam wartość a lub b. console.log ( Fifteen is ${a + b}.); nie zmienia się dynamicznie. zawsze pokazuje, że Piętnastka ma 15 lat.
Dharan,
168

Przed Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, nie, nie było to możliwe w javascript. Musisz uciekać się do:

var hello = "foo";
var my_string = "I pity the " + hello;
Sarfraz
źródło
2
Wkrótce będzie to możliwe w javascript (ES6) z ciągami szablonów, zobacz moją szczegółową odpowiedź poniżej.
bformet
Jest to możliwe, jeśli lubisz pisać CoffeeScript, który faktycznie jest javascript o lepszej składni.
bformet
1
Świetny krzyk dla starszych przeglądarek :)
Kirsty Marks
1
Szkoda FOO !!! to świetnie
Adam Hughes
32

cóż, możesz to zrobić, ale nie jest to szczególnie ogólne

'I pity the $fool'.replace('$fool', 'fool')

Możesz z łatwością napisać funkcję, która robi to inteligentnie, jeśli naprawdę tego potrzebujesz

Scott Evernden
źródło
Właściwie całkiem przyzwoite.
Pan B
1
Ta odpowiedź jest dobra, gdy trzeba przechowywać ciąg szablonu w bazie danych i przetwarzać go na żądanie
Dima Escaroda,
Dobry, działa dobrze. bardzo proste, ale nie przyszło mi do głowy.
Sam
13

Pełna odpowiedź, gotowa do użycia:

 var Strings = {
        create : (function() {
                var regexp = /{([^{]+)}/g;

                return function(str, o) {
                     return str.replace(regexp, function(ignore, key){
                           return (key = o[key]) == null ? '' : key;
                     });
                }
        })()
};

Zadzwoń jako

Strings.create("My firstname is {first}, my last name is {last}", {first:'Neo', last:'Andersson'});

Aby dołączyć go do String.prototype:

String.prototype.create = function(o) {
           return Strings.create(this, o);
}

Następnie użyj jako:

"My firstname is ${first}".create({first:'Neo'});
mmm
źródło
10

Możesz użyć tej funkcji javascript do tego rodzaju szablonów. Nie trzeba dołączać całej biblioteki.

function createStringFromTemplate(template, variables) {
    return template.replace(new RegExp("\{([^\{]+)\}", "g"), function(_unused, varName){
        return variables[varName];
    });
}

createStringFromTemplate(
    "I would like to receive email updates from {list_name} {var1} {var2} {var3}.",
    {
        list_name : "this store",
        var1      : "FOO",
        var2      : "BAR",
        var3      : "BAZ"
    }
);

Wyjście :"I would like to receive email updates from this store FOO BAR BAZ."

Użycie funkcji jako argumentu funkcji String.replace () było częścią specyfikacji ECMAScript v3. Zobacz tę odpowiedź SO, aby uzyskać więcej informacji.

Eric Seastrand
źródło
Czy to jest wydajne?
mmm
Wydajność zależeć będzie w dużej mierze od przeglądarki użytkownika, ponieważ to rozwiązanie deleguje „ciężkie podnoszenie” dopasowania wyrażenia regularnego i zastępowanie ciągów znaków do natywnych funkcji przeglądarki. W każdym razie, ponieważ dzieje się tak po stronie przeglądarki, wydajność nie jest tak dużym problemem. Jeśli chcesz szablonów po stronie serwera (dla Node.JS lub podobnych), powinieneś użyć rozwiązania literałów szablonów ES6 opisanego przez @bformet, ponieważ jest ono prawdopodobnie bardziej wydajne.
Eric Seastrand,
4

Jeśli próbujesz wykonać interpolację do mikrotemplowania, w tym celu podoba mi się Mustache.js .

Joe Martinez
źródło
3

Napisałem ten pakiet npm stringinject https://www.npmjs.com/package/stringinject, który pozwala wykonać następujące czynności

var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);

który zastąpi {0} i {1} elementami tablicy i zwróci następujący ciąg

"this is a test string for stringInject"

lub możesz zastąpić symbole zastępcze kluczami i wartościami obiektów takimi jak:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

"My username is tjcafferkey on Github" 
tjcafferkey
źródło
3

Użyłbym zaznaczenia wstecznego ``.

let name1 = 'Geoffrey';
let msg1 = `Hello ${name1}`;
console.log(msg1); // 'Hello Geoffrey'

Ale jeśli nie wiesz, name1kiedy tworzysz msg1.

Na przykład, jeśli msg1pochodzi z interfejsu API.

Możesz użyć :

let name2 = 'Geoffrey';
let msg2 = 'Hello ${name2}';
console.log(msg2); // 'Hello ${name2}'

const regexp = /\${([^{]+)}/g;
let result = msg2.replace(regexp, function(ignore, key){
    return eval(key);
});
console.log(result); // 'Hello Geoffrey'

Zastąpi ${name2}go jego wartością.

gturquais
źródło
2

Nie widzę tu żadnych zewnętrznych bibliotek, ale Lodash ma _.template(),

https://lodash.com/docs/4.17.10#template

Jeśli już korzystasz z biblioteki, warto to sprawdzić, a jeśli nie korzystasz z Lodash, zawsze możesz wybrać metody z npm, npm install lodash.templateaby zmniejszyć koszty ogólne.

Najprostsza forma -

var compiled = _.template('hello <%= user %>!');
compiled({ 'user': 'fred' });
// => 'hello fred!'

Istnieje również wiele opcji konfiguracji -

_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
var compiled = _.template('hello {{ user }}!');
compiled({ 'user': 'mustache' });
// => 'hello mustache!'

Najbardziej interesujące są niestandardowe ograniczniki.

Mark Carpenter Jr
źródło
0

Utwórz metodę podobną do String.format()Java

StringJoin=(s, r=[])=>{
  r.map((v,i)=>{
    s = s.replace('%'+(i+1),v)
  })
return s
}

posługiwać się

console.log(StringJoin('I can %1 a %2',['create','method'])) //output: 'I can create a method'
Emerson Barcellos
źródło
0

Cytat pokojowy 2020:

Console.WriteLine("I {0} JavaScript!", ">:D<");

console.log(`I ${'>:D<'} C#`)
MatrixRonny
źródło
0

Po prostu użyj:

var util = require('util');

var value = 15;
var s = util.format("The variable value is: %s", value)
Federico Caccia
źródło
-1
String.prototype.interpole = function () {
    var c=0, txt=this;
    while (txt.search(/{var}/g) > 0){
        txt = txt.replace(/{var}/, arguments[c]);
        c++;
    }
    return txt;
}

Uso:

var hello = "foo";
var my_string = "I pity the {var}".interpole(hello);
//resultado "I pity the foo"
Abran Salas Molina
źródło
-2

var hello = "foo";

var my_string ="I pity the";

console.log (my_string, cześć)

lalithya
źródło
1
To nie odpowiada na pytanie. Możesz wylogować oba ciągi w jednym wierszu, ale to nie daje nowego ciągu zawierającego oba ciągi, o co prosi OP.
Max Vollmer,