Bagaimana saya bisa melakukan interpolasi string dalam JavaScript?


536

Pertimbangkan kode ini:

var age = 3;

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

Apakah ada cara lain untuk memasukkan nilai variabel ke dalam string, selain dari penggabungan string?


7
Anda dapat checkout CoffeeScript: coffeescript.org
dennismonsewicz

1
Seperti yang telah ditunjukkan orang lain, metode yang Anda gunakan adalah cara termudah untuk melakukannya. Saya ingin bisa merujuk ke variabel di dalam string, tetapi dalam javascript Anda perlu menggunakan gabungan (atau beberapa pendekatan find / replace lainnya). Orang-orang seperti Anda dan saya mungkin sedikit terlalu terikat pada PHP untuk kebaikan kita sendiri.
Im

4
Gunakan template
Jahan

2
Penggabungan bukan interpolasi dan pengguna bertanya bagaimana melakukan interpolasi. Saya pikir Lev akhirnya memberikan jawabannya, yaitu tidak ada cara untuk melakukan ini di JS asli. Saya tidak mengerti mengapa ini bukan pertanyaan nyata.
gitb

4
Jika saya diizinkan untuk menjawab, sekarang ada solusi yang dimulai untuk juru bahasa yang lebih baru (FF 2015 dan Chrome sudah mendukung): developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Misalnya. Show GRAPH of : ${fundCode}-${funcCode} membuat saya Show GRAPH of : AIP001-_sma (gunakan backticks di sekitar string 1 .... tampaknya tidak dapat ditampilkan di sini)
Marcos

Jawaban:


537

Sejak ES6, Anda dapat menggunakan literal templat :

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

PS Perhatikan penggunaan tanda kutip mundur: ``.


3
Saya bertanya-tanya mengapa mereka menggunakan backtick untuk hal ini, bukankah "$ {age}" cukup untuk melakukan interpolasi?
Laughing Lemonade

5
@LaughingLemonade Kompatibilitas mundur. Jika diimplementasikan seperti itu, semua kode yang ada yang mencetak string dalam format itu akan gagal.
theouroureye

1
@Jonathan Saya selalu tidak suka backticks sebagai karakter yang berarti. Tapi saya tidak yakin apakah alasannya universal atau hanya berlaku untuk tata letak keyboard bahasa saya. Backtick adalah jenis karakter khusus yang menunggu untuk ditulis hingga karakter berikutnya, mengharuskannya dipukul dua kali untuk menulis (dan menulis dua di antaranya saat ini). Ini karena beberapa karakter berinteraksi dengan mereka, seperti "e". Jika saya mencoba menulis "ello" dengan mereka, saya mendapatkan èllo``. Ini juga agak mengganggu (shift + forwardtick, yang merupakan karakter lookahead khusus lainnya), karena memerlukan shift untuk mengetik, tidak seperti '.
felix

@ Feliks itu pemikiran yang khusus untuk tata letak keyboard Anda; apa yang Anda gambarkan disebut "kunci mati". Mereka hadir dalam tata letak keyboard Norwegia (di mana saya berasal) juga, yang merupakan bagian dari alasan saya beralih ke tata letak keyboard AS untuk semua pemrograman. (Ada sejumlah karakter lain - misalnya [dan] - yang jauh lebih mudah pada keyboard AS juga.)
Eivind Eklund

239

tl; dr

Gunakan Template String Literals ECMAScript 2015, jika ada.

Penjelasan

Tidak ada cara langsung untuk melakukannya, sesuai spesifikasi ECMAScript 5, tetapi ECMAScript 6 memiliki string template , yang juga dikenal sebagai quasi-literals selama penyusunan spec. Gunakan seperti ini:

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

Anda dapat menggunakan ekspresi JavaScript apa pun yang valid di dalam {}. Sebagai contoh:

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

Hal penting lainnya adalah, Anda tidak perlu khawatir tentang string multi-line lagi. Anda dapat menuliskannya sebagai

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

Catatan: Saya menggunakan io.js v2.4.0 untuk mengevaluasi semua string templat yang ditunjukkan di atas. Anda juga dapat menggunakan Chrome terbaru untuk menguji contoh yang ditunjukkan di atas.

Catatan: Spesifikasi ES6 sekarang diselesaikan , tetapi belum diimplementasikan oleh semua browser utama.
Menurut halaman Jaringan Pengembang Mozilla , ini akan diterapkan untuk dukungan dasar mulai dari versi berikut: Firefox 34, Chrome 41, Internet Explorer 12. Jika Anda pengguna Opera, Safari, atau Internet Explorer dan ingin tahu tentang ini sekarang , test bed ini dapat digunakan untuk bermain-main sampai semua orang mendapat dukungan untuk ini.


3
Ini dapat digunakan jika Anda menggunakan babeljs , jadi Anda bisa memperkenalkannya dalam basis kode Anda dan kemudian lepaskan langkah transpilasi begitu browser yang Anda perlukan untuk mengimplementasikannya.
ivarni

Apakah ada cara untuk mengkonversi string standar ke string string literal? Misalnya, jika seseorang memiliki file json yang berisi tabel terjemahan yang membutuhkan nilai-nilai yang diinterpolasi ke dalamnya untuk tujuan tampilan? Saya pikir solusi pertama mungkin bekerja dengan baik untuk situasi ini, tapi saya suka sintaks template string yang baru secara umum.
nbering

Karena ini masih salah satu hasil pencarian pertama pada interpolasi string js, alangkah baiknya jika Anda dapat memperbaruinya untuk mencerminkan ketersediaan umum sekarang. "Tidak ada cara langsung untuk melakukannya" mungkin tidak berlaku lagi untuk sebagian besar browser.
Felix Dombek

2
untuk penglihatan yang buruk di penonton, `karakter berbeda dari '. Jika Anda kesulitan membuatnya berfungsi, pastikan Anda menggunakan kutipan kubur, (alias kutipan miring, kutipan belakang) en.wikipedia.org/wiki/Grave_accent . Itu ada di kiri atas keyboard Anda :)
Quincy

@Quincy Kiri bawah keyboard Mac - juga dikenal sebagai centang-kembali :)
RB.

192

JavaScript Perbaikan Douglas Crockford mencakup String.prototype.supplantfungsi. Ini pendek, akrab, dan mudah digunakan:

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' }));

Jika Anda tidak ingin mengubah prototipe String, Anda selalu dapat mengadaptasinya menjadi standalone, atau menempatkannya di ruang nama lain, atau apa pun.


103
Catatan: Ini akan berjalan sepuluh kali lebih lambat daripada hanya menggabungkan.
cllpse

36
Dan perlu sekitar tiga kali lebih banyak penekanan tombol & byte.
ma11hew28

8
@roosteronacid - Bisakah Anda memberikan perspektif tentang penurunan kecepatan itu? Seperti, dari 0,01 hingga 0,1 (penting) atau dari 0,000000001 hingga 0,00000001 (tidak relevan)?
chris

16
@george: Tes cepat pada mesin saya memberi 7312 ns untuk "Sapi itu bilang moo, moo, moo!" menggunakan metode Crockford vs 111 ns untuk fungsi yang dikompilasi yang menarik variabel dari objek yang lewat dan menyatukannya dengan bagian konstan dari string template. Ini adalah Chrome 21.
George

13
Atau gunakan seperti:"The {0} says {1}, {1}, {1}!".supplant(['cow', 'moo'])
Robert Massa

54

Peringatan: hindari sistem templat apa pun yang tidak memungkinkan Anda keluar dari pembatasnya sendiri. Sebagai contoh, Tidak akan ada cara untuk menghasilkan yang berikut menggunakan supplant()metode yang disebutkan di sini.

"Saya berumur 3 tahun berkat variabel {usia} saya."

Interpolasi sederhana dapat bekerja untuk skrip mandiri kecil, tetapi sering disertai dengan cacat desain ini yang akan membatasi penggunaan serius. Saya jujur ​​lebih suka template DOM, seperti:

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

Dan gunakan manipulasi jQuery: $('#age').text(3)

Sebagai alternatif, jika Anda hanya bosan dengan penggabungan string, selalu ada sintaks alternatif:

var age = 3;
var str = ["I'm only", age, "years old"].join(" ");

4
Catatan: Array.join()lebih lambat daripada +penggabungan langsung ( gaya), karena mesin peramban (yang mencakup V8, yang mencakup simpul dan hampir semua yang menjalankan JS hari ini) telah mengoptimalkannya secara besar-besaran dan ada banyak perbedaan dalam mendukung penggabungan langsung
pilau

1
Metode supplant memang memungkinkan Anda untuk menghasilkan string yang Anda sebutkan: {token} hanya diganti jika objek data berisi anggota yang disebut token- sehingga asalkan Anda tidak menyediakan objek data yang memiliki ageanggota, itu akan baik-baik saja.
Chris Fewtrell

1
Chris, saya tidak melihat bagaimana itu solusinya. Saya dapat dengan mudah memperbarui contoh untuk menggunakan variabel usia dan string {usia}. Apakah Anda benar-benar ingin khawatir tentang apa yang dapat Anda beri nama variabel Anda berdasarkan teks salinan templat? --Juga, sejak posting ini saya sudah menjadi penggemar berat perpustakaan pengikat data. Beberapa, seperti RactiveJS, akan menyelamatkan Anda dari DOM yang sarat dengan rentang variabel. Dan tidak seperti Moustache, itu hanya memperbarui bagian halaman.
greg.kindel

3
Jawaban utama Anda tampaknya menganggap bahwa javascript ini berjalan di lingkungan peramban meskipun pertanyaannya tidak ditandai dengan HTML.
kanon

2
"Kata hati-hati" Anda tentang supplanttidak beralasan: "I am 3 years old thanks to my {age} variable.".supplant({}));mengembalikan persis string yang diberikan. Jika agediberikan, orang masih dapat mencetak {dan }menggunakan{{age}}
le_m

23

Coba pustaka sprintf (implementasi sprintf JavaScript sumber terbuka lengkap). Sebagai contoh:

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

vsprintf mengambil array argumen dan mengembalikan string yang diformat.


22

Saya menggunakan pola ini dalam banyak bahasa ketika saya belum tahu bagaimana melakukannya dengan benar dan hanya ingin mendapatkan ide dengan cepat:

// 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')
    ;

Meskipun tidak terlalu efisien, saya menemukannya dapat dibaca. Selalu berhasil, dan selalu tersedia:

' 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")

SELALU

* 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'



6

Coba kiwi , modul JavaScript ringan untuk interpolasi string.

Anda dapat melakukan

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

atau

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

6

Jika Anda ingin menginterpolasi dalam console.logoutput, maka cukup

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

Di sini, %sadalah apa yang disebut "format specifier". console.logmemiliki dukungan interpolasi semacam ini.


1
Ini satu-satunya jawaban yang benar. Pertanyaannya adalah tentang interpolasi, bukan templat string.
sospedra

5

Inilah solusi yang mengharuskan Anda untuk memberikan objek dengan nilai-nilai. Jika Anda tidak memberikan objek sebagai parameter, itu akan menjadi default untuk menggunakan variabel global. Tapi lebih baik tetap menggunakan parameter, jauh lebih bersih.

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>


3
Jangan gunakan eval, evalitu jahat!
chris97ong

5
@ chris97ong Sementara itu "benar", setidaknya berikan alasan ("jahat" tidak membantu) atau solusi alternatif. Hampir selalu ada jalan untuk menggunakannya eval, tetapi terkadang tidak. Sebagai contoh, jika OP ingin cara interpolasi menggunakan lingkup saat ini, tanpa harus melewati objek pencarian (seperti bagaimana interpolasi Groovy bekerja), saya cukup yakin evalakan diperlukan. Jangan hanya menggunakan "eval is evil" lama.
Ian

1
tidak pernah menggunakan eval atau menyarankan untuk digunakan
hasen

2
@ memiliki ini mengapa saya mengatakannya "mungkin bukan ide terbaik" dan menyediakan metode alternatif. Namun sayangnya, evaladalah satu-satunya cara untuk mengakses variabel lokal dalam ruang lingkup . Jadi jangan menolaknya hanya karena itu melukai perasaan Anda. BTW, saya juga lebih suka cara alternatif karena lebih aman, tetapi evalmetode inilah yang tepat menjawab pertanyaan OP, oleh karena itu ada dalam jawabannya.
Lucas Trzesniewski

1
Masalahnya evaladalah bahwa tidak dapat mengakses vars dari lingkup lain, jadi jika .interpolatepanggilan Anda berada dalam fungsi lain, dan bukan global, itu tidak akan berfungsi.
georg

2

Memperluas jawaban kedua Greg Kindel , Anda dapat menulis sebuah fungsi untuk menghilangkan beberapa lapisan boiler:

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

Pemakaian:

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!');

1

Saya dapat menunjukkan kepada Anda sebuah contoh:

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'));


1

Sejak ES6, jika Anda ingin melakukan interpolasi string dalam kunci objek, Anda akan mendapatkan SyntaxError: expected property name, got '${'jika Anda melakukan sesuatu seperti:

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

Anda sebaiknya melakukan yang berikut:

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

1

Tambahan lebih banyak untuk versi ES6 dari pos @Chris Nielsen.

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."

0

Menggunakan sintaks template gagal di browser lama, penting jika Anda membuat HTML untuk penggunaan umum. Menggunakan concatenation itu membosankan dan sulit dibaca, terutama jika Anda memiliki banyak ekspresi atau panjang, atau jika Anda harus menggunakan tanda kurung untuk menangani campuran item angka dan string (keduanya menggunakan operator +).

PHP memperluas string yang dikutip yang berisi variabel dan bahkan beberapa ekspresi menggunakan notasi yang sangat kompak: $a="the color is $color";

Dalam JavaScript, fungsi yang efisien dapat ditulis untuk mendukung ini:, var a=S('the color is ',color);menggunakan sejumlah variabel argumen. Meskipun tidak ada keuntungan dibandingkan penggabungan dalam contoh ini, ketika ekspresi menjadi lebih panjang sintaks ini mungkin lebih jelas. Atau seseorang dapat menggunakan tanda dolar untuk memberi sinyal awal ekspresi menggunakan fungsi JavaScript, seperti dalam PHP.

Di sisi lain, menulis fungsi penyelesaian yang efisien untuk menyediakan perluasan string seperti template untuk browser lama tidak akan sulit. Seseorang mungkin sudah melakukannya.

Akhirnya, saya membayangkan sprintf (seperti dalam C, C ++, dan PHP) dapat ditulis dalam JavaScript, meskipun akan sedikit kurang efisien daripada solusi lain ini.


0

Interpolasi fleksibel khusus:

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>


0

Meskipun templat mungkin yang terbaik untuk kasus yang Anda gambarkan, jika Anda memiliki atau menginginkan data dan / atau argumen dalam bentuk iterable / array, Anda dapat menggunakannya String.raw.

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

Dengan data sebagai array, seseorang dapat menggunakan operator spread:

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

0

Tidak dapat menemukan apa yang saya cari, kemudian menemukannya -

Jika Anda menggunakan Node.js, ada utilpaket bawaan dengan fungsi format yang berfungsi seperti ini:

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

Secara kebetulan ini sekarang dibangun ke dalam console.lograsa juga di Node.js -

console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.