如何在JavaScript中进行字符串插值?

Tom*_*man 464 javascript string string-interpolation

考虑以下代码:

var age = 3;

console.log("I'm " + age + " years old!");
Run Code Online (Sandbox Code Playgroud)

除了字符串连接之外,还有其他方法可以将变量的值插入字符串吗?

Dam*_*ica 447

从ES6开始,您可以使用模板文字:

const age = 3
console.log(`I'm ${age} years old!`)
Run Code Online (Sandbox Code Playgroud)

PS注意使用反引号:``.

  • 对于其他任何想知道为什么他们无法让它工作的人,请注意使用后退滴答. (74认同)
  • 有趣的是,这打破了StackOverflow的语法高亮 (31认同)
  • 我想知道为什么他们在这上面加上反引号,“${age}”不足以进行插值吗? (12认同)
  • @thefourtheye他们可以遵循C#的方式……`$“你好,{name}!” (4认同)
  • @LaughingLemonade向后兼容性.如果以这种方式实现,那么以该格式打印字符串的所有现有代码都将失败. (3认同)
  • 这也不适用于IE11. (2认同)
  • @Jonathan 我总是不喜欢反引号作为一个有意义的角色。但我不确定原因是普遍存在还是仅适用于我的语言键盘布局。Backtick 是一种特殊的字符,它等待写入直到下一个字符,要求它被击中两次才能写入(并且此时写入其中两个)。这是因为某些字符与它们交互,例如“e”。如果我尝试和他们一起写“ello”,我会得到 èllo``。它的位置也有点烦人(shift+forwardtick,这是另一个这样特殊的前瞻字符),因为它需要 shift 才能键入,与 '. (2认同)
  • @felix这是一个特定于你的键盘布局的想法;您所描述的称为“死键”。它们也出现在挪威键盘布局(我来自哪里)中,这也是我在所有编程中切换到美国键盘布局的部分原因。(还有许多其他字符 - 例如 [ 和 ] - 在美国键盘上也更容易使用。) (2认同)
  • @felix Protip:我使用的是挪威键盘,它具有您所描述的确切功能。您可以在点击反引号后点击空格来简单地“使其显示”,而无需将其放在字符上方或强制使用两个反引号。:) (2认同)

the*_*eye 229

TL;博士

如果适用,请使用ECMAScript 2015的模板字符串文字.

说明

根据ECMAScript 5规范,没有直接的方法可以做到这一点,但ECMAScript 6有模板字符串,在规范的起草过程中也被称为准文字.像这样使用它们:

> var n = 42;
undefined
> `foo${n}bar`
'foo42bar'
Run Code Online (Sandbox Code Playgroud)

您可以在其中使用任何有效的JavaScript表达式{}.例如:

> `foo${{name: 'Google'}.name}bar`
'fooGooglebar'
> `foo${1 + 3}bar`
'foo4bar'
Run Code Online (Sandbox Code Playgroud)

另一件重要的事情是,您不必再担心多行字符串了.你可以简单地把它们写成

> `foo
...     bar`
'foo\n    bar'
Run Code Online (Sandbox Code Playgroud)

注意:我使用io.js v2.4.0来评估上面显示的所有模板字符串.您还可以使用最新的Chrome来测试上面显示的示例.

注意: ES6规范现已最终确定,但尚未由所有主流浏览器实施.
根据Mozilla开发者网络页面,这将实现从以下版本开始的基本支持:Firefox 34,Chrome 41,Internet Explorer 12.如果您是Opera,Safari或Internet Explorer用户,现在对此感到好奇,这个测试床可以用来玩,直到每个人都得到支持.

  • 如果您使用[babeljs](https://goo.gl/8HHxG0),它可以使用,因此您可以在代码库中引入它,然后在您需要支持的浏览器实现它之后再删除转换步骤. (3认同)
  • 对于观众视力不佳的人来说,"性格不同于".如果您无法使用此功能,请确保使用严重的报价(也称为倾斜报价,返回报价)https://en.wikipedia.org/wiki/Grave_accent.它位于键盘的左上角:) (2认同)

Chr*_*sen 186

Douglas Crockford的Remedial 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' }));
Run Code Online (Sandbox Code Playgroud)

如果您不想更改String的原型,您可以始终将其调整为独立的,或将其放入其他名称空间或其他任何名称空间.

  • 注意:这比连接慢十倍. (102认同)
  • 并且需要大约三倍的击键次数和字节数. (35认同)
  • @george:我的机器上的快速测试给了7312 ns的"牛说moo,moo,moo!" 使用Crockford的方法vs 111 ns进行预编译函数,该函数将变量拉出传递的对象并将它们与模板字符串的常量部分连接起来.这是Chrome 21. (15认同)
  • 或者使用它:""{0}说{1},{1},{1}!".取代(['cow','moo']) (12认同)
  • @roosteronacid - 你能否对速度降低有所了解?例如,从0.01s到0.1s(重要)或从0.000000001s到0.00000001s(不相关)? (8认同)
  • 我想,像 PHP 或 Ruby 这样的语法级别的普通插值在解析代码时只会将插值解析为通常的串联。另一方面,该解决方案意味着多个子字符串搜索。 (2认同)

gre*_*del 52

注意事项:避免使用任何不允许你逃避自己的分隔符的模板系统.例如,使用supplant()此处提到的方法无法输出以下内容.

"感谢我的{age}变量,我已经3岁了."

简单插值可能适用于小型自包含脚本,但通常会出现这种设计缺陷,限制任何严重的使用.老实说,我更喜欢DOM模板,例如:

<div> I am <span id="age"></span> years old!</div>
Run Code Online (Sandbox Code Playgroud)

并使用jQuery操作: $('#age').text(3)

或者,如果您只是厌倦了字符串连接,那么总会有替代语法:

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

  • 旁注:`Array.join()`比直接(`+`样式)连接慢,因为浏览器引擎(包括V8,包括节点和几乎所有运行JS的东西)已经大量优化它并且有很多优点支持[直接连接]的差异(http://jsperf.com/string-concatenation/47) (3认同)
  • 你的主要答案似乎是假设这个javascript在浏览器环境中运行,即使问题没有用HTML标记. (3认同)
  • 关于"取代"的"谨慎"是没有根据的:"我感谢我的{age}变量,我已经3岁了.".supplant({}));`完全返回给定的字符串.如果给出`age`,仍然可以使用`{{age}}`打印`{`和`}` (2认同)

Naw*_*Man 23

试试sprintf.例如:

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


shu*_*ter 21

你可以使用Prototype的模板系统,如果你真的想用大锤来破解坚果:

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


Jef*_*ave 18

当我不知道如何正确地使用这种模式时,我会在很多语言中使用这种模式,只是想快速得到一个想法:

// 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')
    ;
Run Code Online (Sandbox Code Playgroud)

虽然不是特别有效,但我发现它可读.它始终有效,并且始终可用:

' 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")
Run Code Online (Sandbox Code Playgroud)

总是

* 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'
Run Code Online (Sandbox Code Playgroud)

  • IE 不支持模板文字,因此当您不想需要单独的包(例如 sprintf)时,这是一个很好的解决方案。比连接字符串干净得多,尤其是在处理具有动态属性和内容的 html 标签时。 (2认同)

小智 17

最简单的是

`my string ${VARIABLE}`
Run Code Online (Sandbox Code Playgroud)

实现此目的效率较低的方法是

function format(str, ...params) {
  for(const param of params)
    str = str.replace("%", param);
   return str;
}
Run Code Online (Sandbox Code Playgroud)

可以与

format("My % string", "interpolation")
Run Code Online (Sandbox Code Playgroud)


Moh*_*rif 11

你可以轻松地使用ES6 template string并使用任何可用的transila像babel一样转换到ES5.

const age = 3;

console.log(`I'm ${age} years old!`);
Run Code Online (Sandbox Code Playgroud)

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


小智 10

let age = 3;

console.log(`I'm ${age} years old!`);
Run Code Online (Sandbox Code Playgroud)

您可以使用反引号``ES6模板字符串


zs2*_*020 6

试试kiwi,一个用于字符串插值的轻量级JavaScript模块.

你可以做

Kiwi.compose("I'm % years old!", [age]);
Run Code Online (Sandbox Code Playgroud)

要么

Kiwi.compose("I'm %{age} years old!", {"age" : age});
Run Code Online (Sandbox Code Playgroud)


Luc*_*ski 5

这是一个需要您为对象提供值的解决方案.如果不提供对象作为参数,则默认使用全局变量.但更好地坚持使用参数,它更清洁.

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();
Run Code Online (Sandbox Code Playgroud)
<div id="resultA"></div><div id="resultB"></div>
Run Code Online (Sandbox Code Playgroud)

  • @ chris97ong虽然这是"真实的",但至少给出一个理由("邪恶"没有帮助)或替代解决方案.使用`eval`几乎总是有办法,但有时候没有.例如,如果OP想要一种使用当前作用域进行插值的方法,而不必传递查找对象(就像Groovy插值的工作原理那样),我很确定需要`eval`.不要只是诉诸旧的"eval is evil". (4认同)
  • 不要使用'eval`,'eval`是邪恶的! (3认同)
  • @hasenj这就是为什么我说它"可能不是最好的主意"*并提供了另一种方法.但不幸的是,**`eval`是访问范围**中局部变量的唯一方法.所以不要因为它伤害你的感情而拒绝它.顺便说一句,我也更喜欢替代方式,因为它更安全,但是'eval`方法正是*精确地回答了OP的问题,因此它就在答案中. (2认同)

小智 5

如果要对console.log输出进行插值,则只需

console.log("Eruption 1: %s", eruption1);
                         ^^
Run Code Online (Sandbox Code Playgroud)

在这里,%s就是所谓的“格式说明符”。console.log具有内置的这种插值支持。


小智 5

找不到我要找的东西,然后找到了 -

如果您使用的是 Node.js,则有一个带有格式函数的内置util包,其工作方式如下:

util.format("Hello my name is %s", "Brent");
> Hello my name is Brent
Run Code Online (Sandbox Code Playgroud)

巧合的是,现在 Node.js 中也内置了此console.log功能 -

console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
Run Code Online (Sandbox Code Playgroud)