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

796

考虑以下代码:

var age = 3;

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

除了使用字符串拼接,还有其他方式将变量的值插入到字符串中吗?


7
你可以查看 CoffeeScript:http://coffeescript.org/。 - dennismonsewicz
2
正如其他人所指出的那样,你正在使用的方法确实是最简单的方法。我很想能够在字符串内引用变量,但在JavaScript中,你需要使用连接(或其他查找/替换方法)。像你和我这样的人可能对PHP有点太依赖了。 - SikoSoft
4
使用Underscore.js template - Jahan Zinedine
3
连接不等同于插值,用户询问如何执行插值。我认为Lev最终提供了答案,即在JS原生中没有办法做到这一点。我不明白为什么这不是一个真正的问题。 - gitb
5
如果我被允许回答,现在有一种解决方案可供新的解释器使用(2015年的FF和Chrome已经支持):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings。例如,``Show GRAPH of: ${fundCode}-${funcCode}`` 将给我 Show GRAPH of : AIP001-_sma (在字符串1周围使用反引号,无法在此处显示)。 - Marcos
显示剩余6条评论
22个回答

9
let age = 3;

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

你可以使用反引号``和ES6模板字符串。

6

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

你可以这样做:

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

或者

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

6

以下是一种解决方案,需要您提供一个包含值的对象作为参数。如果不提供对象作为参数,它将默认使用全局变量。但最好使用参数,这样更加清晰易懂。

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
不要使用eval,它是有害的! - chris97ong
5
虽然这是“正确”的,但至少给出一个理由(“邪恶”没有帮助)或替代方案。几乎总有一种方法可以避免使用eval,但有时候也不行。例如,如果发帖者想要一种方式来使用当前作用域进行插值,而不必传递查找对象(就像Groovy插值的工作方式),我确信需要使用eval。不要只是诉诸于老掉牙的“eval 是邪恶的”。 - Ian
1
永远不要使用eval,也永远不要建议使用它。 - hasen
3
这就是我说它“可能不是最好的主意”并提供另一种替代方法的原因。但不幸的是,“eval”是访问作用域内局部变量的唯一方式。所以不要因为它伤害了你的感情而拒绝它。顺便说一下,我也更喜欢另一种替代方法,因为它更安全,但“eval”方法正是精确回答了OP的问题,因此它在答案中。 - Lucas Trzesniewski
1
“eval” 的问题在于它无法访问另一个作用域中的变量,因此如果您的 “.interpolate” 调用位于另一个函数而不是全局范围内,则不起作用。 - georg
显示剩余2条评论

4

一开始没找到想要的,后来找到了 -

如果你使用Node.js,内置有一个名为util的包,其中有一个格式化函数,用法如下:

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

巧合的是,在Node.js中,这个功能也被集成到console.log里了。
console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError

2

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

2
我可以通过一个例子来向您展示:

我可以用一个例子来说明:

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

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

1
自从ES6以来,如果你想在对象键中进行字符串插值,如果你做了类似以下的操作,你将会得到一个 SyntaxError: expected property name, got '${'
let age = 3
let obj = { `${age}`: 3 }

你应该做以下事情:
let obj = { [`${age}`]: 3 }

0

如果你正在创建公共使用的HTML,那么在旧版浏览器中使用模板语法会失败,这一点非常重要。使用连接操作很繁琐且难以阅读,特别是当你有许多或长表达式时,或者必须使用括号来处理数字和字符串项的混合(两者都使用+运算符)。

PHP使用非常紧凑的符号扩展带有变量甚至某些表达式的引用字符串:$a="the color is $color";

在JavaScript中,可以编写一个高效的函数来支持此操作:var a=S('the color is ',color);,使用可变数量的参数。虽然在这个例子中与连接操作相比没有优势,但当表达式变得更长时,这种语法可能更清晰。或者,可以使用美元符号来表示使用JavaScript函数开始表达式,就像在PHP中一样。

另一方面,为旧版浏览器编写一个有效的解决方案函数以提供类似模板的字符串扩展并不难。可能已经有人做过了。

最后,我想象sprintf(如C、C++和PHP中所示)可以在JavaScript中编写,尽管它可能比其他解决方案稍微低效一些。


0

自定义灵活的插值:

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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接