Как я могу выполнить интерполяцию строк в JavaScript?

Рассмотрим этот код:

var age = 3;

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

Есть ли другие способы вставки значения переменной в строку, кроме конкатенации строк?

Ответ 1

Начиная с ES6, вы можете использовать литералы шаблона:

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

Ответ 2

TL;DR

Используйте литералы строк шаблона ECMAScript 2015, если применимо.

Описание

Нет прямого способа сделать это в соответствии со спецификациями ECMAScript 5, но ECMAScript 6 имеет строки шаблона, которые также были известны как квазилитералов при составлении спецификации. Используйте их следующим образом:

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

Вы можете использовать любое допустимое выражение JavaScript внутри {}. Например:

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

Другое важное: вам больше не нужно беспокоиться о многострочных строках. Вы можете написать их просто как

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

Примечание. Я использовал io.js v2.4.0 для оценки всех строк шаблонов, показанных выше. Вы также можете использовать последнюю версию Chrome для тестирования приведенных выше примеров.

Примечание. Спецификации ES6 теперь завершены, но еще не реализованы всеми основными браузерами.
Согласно страницам сети разработчиков Mozilla, это будет реализовано для базовой поддержки, начиная с следующих версий: Firefox 34, Chrome 41, Internet Explorer 12. Если вы являетесь пользователем Opera, Safari или Internet Explorer, и теперь вам интересно, этот тестовый стенд можно использовать, пока все не получат поддержку для этого.

Ответ 3

Дуглас Крокфорд Исправленный JavaScript включает функцию String.prototype.supplant. Он короткий, знакомый и простой в использовании:

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

Если вы не хотите изменять прототип String, вы всегда можете адаптировать его к автономному, или поместить его в другое пространство имен или что-то еще.

Ответ 4

Осторожно: избегайте использования любой системы шаблонов, которая не позволит вам избежать собственных разделителей. Например, Невозможно вывести следующее, используя метод supplant(), упомянутый здесь.

"Мне 3 года благодаря моей переменной" возраст ".

Простая интерполяция может работать для небольших автономных скриптов, но часто приходит с этим недостатком дизайна, который ограничит любое серьезное использование. Я честно предпочитаю шаблоны DOM, например:

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

И используйте манипуляции jQuery: $('#age').text(3)

В качестве альтернативы, если вы просто устали от конкатенации строк, всегда есть альтернативный синтаксис:

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

Ответ 5

Попробуйте sprintf. Например:

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

Ответ 6

Вы можете использовать Prototype template system, если вам действительно нравится использовать кувалду для взлома гайки:

var template = new Template("I'm #{age} years old!");
alert(template.evaluate({age: 21}));

Ответ 7

Я использую этот шаблон на многих языках, когда я еще не знаю, как это сделать правильно, и просто хочу быстро изложить идею:

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

Хотя это не особенно эффективно, я нахожу это читабельным. Это всегда работает и всегда доступно:

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

ВСЕГДА

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

Ответ 8

Вы легко можете использовать ES6 template string и перевести на ES5 с помощью любого доступного трансляционного, такого как babel.

const age = 3;

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

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

Ответ 9

Попробуйте kiwi, легкий модуль JavaScript для строковой интерполяции.

Вы можете сделать

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

или

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

Ответ 10

Вот решение, которое требует, чтобы вы предоставили объект со значениями. Если вы не предоставляете объект в качестве параметра, он будет использовать глобальные переменные по умолчанию. Но лучше придерживаться использования параметра, он намного чище.

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>

Ответ 12

Если вы хотите интерполировать в вывод console.log, то просто

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

Здесь %s - это так называемый "спецификатор формата". console.log имеет встроенную встроенную поддержку интерполяции.

Ответ 13

Другой кувалдой: jquery-tmpl (шаблонизация с помощью jQuery).

Ответ 14

Развернувшись на втором ответе Грега Кинделя, вы можете написать функцию, чтобы исключить часть шаблона:

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

Использование:

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

Ответ 15

Я могу показать вам пример:

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

Ответ 16

Начиная с ES6, если вы хотите выполнить интерполяцию строк в ключах объектов, вы получите SyntaxError: expected property name, got '${' если вы сделаете что-то вроде:

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

Вместо этого вы должны сделать следующее:

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

Ответ 17

Использование синтаксиса шаблона не работает в старых браузерах, что важно, если вы создаете HTML для публичного использования. Использование конкатенации является утомительным и трудным для чтения, особенно если у вас много или длинные выражения или если вы должны использовать скобки для обработки сочетаний чисел и строковых элементов (оба из которых используют оператор +).

PHP расширяет строки в кавычках, содержащие переменные и даже некоторые выражения, используя очень компактную запись: $a="the color is $color";

В JavaScript эффективная функция может быть написана для поддержки этого: var a=S('the color is ',color); , используя переменное количество аргументов. Хотя в этом примере нет преимущества перед конкатенацией, когда выражения становятся длиннее, этот синтаксис может быть более понятным. Или можно использовать знак доллара, чтобы обозначить начало выражения с помощью функции JavaScript, как в PHP.

С другой стороны, написание эффективной обходной функции, обеспечивающей шаблонное расширение строк для старых браузеров, не составило бы труда. Возможно, кто-то уже сделал это.

Наконец, я представляю, что sprintf (как в C, C++ и PHP) может быть написан на JavaScript, хотя он будет немного менее эффективным, чем эти другие решения.

Ответ 18

Замените больше для ES6 версии сообщения @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."

Ответ 19

Настраиваемая гибкая интерполяция:

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 no "closing" match to this part, rebuild it
    if( s1 == s2[0]) return interpolator[0] + s2[0]
    // if this split 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>