考虑以下代码:
var age = 3;
console.log("I'm " + age + " years old!");
除了字符串连接之外,还有其他方法可以将变量的值插入到字符串中吗?
Show GRAPH of : ${fundCode}-${funcCode}
让我Show GRAPH of : AIP001-_sma
(在字符串1周围使用反引号。...似乎无法在此处显示)
考虑以下代码:
var age = 3;
console.log("I'm " + age + " years old!");
除了字符串连接之外,还有其他方法可以将变量的值插入到字符串中吗?
Show GRAPH of : ${fundCode}-${funcCode}
让我Show GRAPH of : AIP001-_sma
(在字符串1周围使用反引号。...似乎无法在此处显示)
Answers:
如果适用,请使用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 Explorer12。如果您是Opera,Safari或Internet Explorer用户,现在对此感到好奇,这个测试床可以用于游戏,直到每个人都对此表示支持。
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' }));
如果您不想更改String的原型,则始终可以将其改编为独立的,或将其放置在其他命名空间中,或其他任何形式。
"The {0} says {1}, {1}, {1}!".supplant(['cow', 'moo'])
警告:避免使用任何模板系统不允许您转义其分隔符。例如,使用supplant()
这里提到的方法将无法输出以下内容。
“由于我的{age}变量,我才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(" ");
token
-因此,只要您不提供具有age
成员的数据对象,就可以了。
supplant
是不必要的:"I am 3 years old thanks to my {age} variable.".supplant({}));
完全返回给定的字符串。如果age
给出了,仍然可以打印{
和}
使用{{age}}
如果您确实想使用大锤破解螺母,则可以使用Prototype的模板系统:
var template = new Template("I'm #{age} years old!");
alert(template.evaluate({age: 21}));
当我尚不知道如何正确执行此模式时,我想在许多语言中使用此模式,而只是想快速了解一下:
// 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'
您可以轻松地使用ES6 template string
并使用任何可用的Transpilar(如babel)将其转换为ES5。
const age = 3;
console.log(`I'm ${age} years old!`);
如果要对console.log
输出进行插值,则只需
console.log("Eruption 1: %s", eruption1);
^^
在这里,%s
就是所谓的“格式说明符”。console.log
具有内置的这种插值支持。
这是一个解决方案,要求您为对象提供值。如果不提供对象作为参数,则默认使用全局变量。但是最好还是坚持使用参数,因为它更干净。
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>
eval
,eval
是邪恶的!
eval
,但有时没有。例如,如果OP想要一种使用当前范围进行插值的方法,而不必传递查找对象(例如Groovy插值的工作方式),那么我肯定eval
会需要。不要只求助于旧的“评估是邪恶的”。
eval
是访问scope中的局部变量的唯一方法。因此,不要仅仅因为它会伤害您的感觉而拒绝它。顺便说一句,我也更喜欢替代方法,因为它更安全,但是该eval
方法恰好回答了OP的问题,因此就在答案中。
eval
在于无法从另一个作用域访问var,因此,如果您的.interpolate
调用位于另一个函数内,而不是全局函数内,则它将无法正常工作。
扩展Greg Kindel的第二个答案,您可以编写一个函数来消除一些样板:
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!');
我可以举一个例子给你看:
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'));
为@Chris Nielsen的帖子的ES6版本替换更多内容。
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."
在较旧的浏览器中,无法使用模板语法,如果要创建供公众使用的HTML,则很重要。使用串联是一个繁琐且难以阅读的过程,特别是如果您有很多或很长的表达式,或者您必须使用括号来处理数字和字符串项的混合(两者都使用+运算符)时,尤其如此。
PHP使用非常紧凑的表示法扩展了包含变量甚至某些表达式的带引号的字符串: $a="the color is $color";
在JavaScript中,可以编写有效的函数来支持此功能:var a=S('the color is ',color);
使用可变数量的参数。尽管在此示例中没有比串联的优势,但是当表达式变长时,此语法可能会更清晰。或者,可以像PHP中一样,使用JavaScript函数使用美元符号来表示表达式的开始。
另一方面,编写有效的解决方法功能以为较旧的浏览器提供类似模板的字符串扩展并不难。可能有人已经做到了。
最后,我想像sprintf(在C,C ++和PHP中)可以用JavaScript编写,尽管它的效率比其他解决方案要低一些。
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>
虽然模板可能最适合您描述的情况,但是如果您具有或想要以可迭代/数组形式的数据和/或参数,则可以使用String.raw
。
String.raw({
raw: ["I'm ", " years old!"]
}, 3);
将数据作为数组,可以使用散布运算符:
const args = [3, 'yesterday'];
String.raw({
raw: ["I'm ", " years old as of ", ""]
}, ...args);