ES6模板文字与串联字符串


84

我有以下Ecma-Script-6代码 template literals

let person = {name: 'John Smith'};   
let tpl = `My name is ${person.name}.`;    
let MyVar="My name is "+ person.name+".";

console.log("template literal= "+tpl);  
console.log("my variable = "+MyVar);

输出如下:

template literal= My name is John Smith.
my variable = My name is John Smith.

这个是小提琴。我尝试搜索确切的差异,但找不到它,我的问题是这两个语句之间有什么区别,

  let tpl = `My name is ${person.name}.`;    

  let MyVar = "My name is "+ person.name+".";

我已经可以在此处将字符串MyVar串联起来person.name了,那么使用模板文字的方案是什么?


8
这是其他语言的共同功能,大约需要时间!看起来更干净,并且是多行的。
elclanrs 2014年

5
不知道您所说的“差异”是什么意思tpl === MyVar?唯一的区别是它们使用的语法。请注意,与字符串连接相反,模板还提供了可用于自动转义之类的标记功能。
Bergi 2014年

您基本上是在问字符串内插与字符串串联之间的区别是什么。
Damjan Pavlica

Answers:


104

如果`Hello ${person.name}`像问题示例中那样仅将模板文字与占位符(例如)一起使用,则结果与串联字符串相同。从主观上讲,它看起来更好并且更易于阅读,尤其是对于多行字符串或包含这两者的字符串'"因为您不必再​​转义那些字符了。

可读性是一个很棒的功能,但是关于模板最有趣的是Tagged模板文字

let person = {name: 'John Smith'}; 
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];  
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!

在此示例的第三行中,名为的函数tag被调用。模板字符串的内容分为多个变量,您可以在tag函数的参数中访问这些变量:文字部分(在此示例中,strArr[0]isMy name is的值和strArr[1]is的值!)和替代项(John Smith)。模板文字将被评估为tag函数返回的。

ECMAScript的维基列出了一些可能的使用情况下,如自动转义或编码输入,或定位。您可以创建一个名为的标记函数msg,该函数查找类似的文字部分My name is,并用当前语言环境的语言(例如德语)的翻译替换它们:

console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.

标记函数返回的值甚至不必是字符串。您可以创建一个名为的标记函数$,该函数对字符串进行求值并将其用作查询选择器以返回DOM节点的集合,如以下示例所示

$`a.${className}[href=~'//${domain}/']`

2
真好!如果那里还有另一个模板文字,例如$ {person.message},它将被翻译吗?
Rigotti 2014年

1
@Rigotti取决于msg函数的实现。您当然也可以转换替换值。
kapex 2014年

@Beat整个ecmascript.org网站似乎都关闭了。我认为他们还是打算放弃他们的Wiki,所以我已经用归档版本更新了链接。
kapex '17

我尝试a.${className}[href=~'//${domain}/']在chrome控制台中运行$ (并在之前className=''和之前进行设置,domain=''但我没有得到DOM节点,而是字符串数组:/(在另一个hadn中,在jsfiddle中,我们在控制台中出错:jsfiddle.net/d1fkta76 “ Uncaught ReferenceError :没有定义$”-为什么?
KamilKiełczewski18年

2
@AniketSuryavanshi这是模板字符串与串联性能的比较:stackoverflow.com/a/29083467/897024几年前,模板字符串速度较慢,但​​看起来比现在的串联快一些。
kapex '19

16

ES6提出了一种新型的字符串文字,使用`反引号作为分隔符。这些文字确实允许嵌入基本的字符串插值表达式,然后对其进行自动分析和评估。

let actor = {name: 'RajiniKanth', age: 68};

let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
  "<p>I am " + actor.age + " old</p>\n";

let newWayHtmlStr =
 `<p>My name is ${actor.name},</p>
  <p>I am ${actor.age} old</p>`;

console.log(oldWayStr);
console.log(newWayHtmlStr);

如您所见,我们在一系列字符周围使用了..``,这些字符被解释为字符串文字,但是该形式的任何表达式都将${..}立即进行内联解析和求值。

插值字符串文字的一个非常不错的好处是允许它们分成多行:

var Actor = {"name" : "RajiniKanth"};

var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!

内插表达式

任何有效的表达式都可以出现${..}在插值字符串的内部lit‐ eral,包括函数调用,内联函数表达式调用,甚至其他interpo‐ lated string literals

function upper(s) {
 return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!

在这里,当将who变量与"s"字符串(而不是who +“ s”组合在一起)时,内部的$ {who} s``内插字符串文字为我们提供了更好的便利。另外要注意的是插值字符串文字正好lexically scoped出现dynamically scoped在其中,而不是以任何方式出现

function foo(str) {
 var name = "foo";
 console.log( str );
}
function bar() {
 var name = "bar";
 foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"

template literal通过减少烦恼,使用HTML绝对可以提高可读性。

普通的旧方法:

'<div class="' + className + '">' +
  '<p>' + content + '</p>' +
  '<a href="' + link + '">Let\'s go</a>'
'</div>';

ES6

`<div class="${className}">
  <p>${content}</p>
  <a href="${link}">Let's go</a>
</div>`
  • 您的字符串可以跨越多行。
  • 您不必转义引号字符。
  • 您可以避免类似“>”的分组
  • 您不必使用加号运算符。

标记模板文字

我们还可以标记template字符串,当标记了字符串时templateliterals和替换将传递给函数,该函数返回结果值。

function myTaggedLiteral(strings) {
  console.log(strings);
}

myTaggedLiteral`test`; //["test"]

function myTaggedLiteral(strings,value,value2) {
  console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5

我们可以使用 spread这里运算符来传递多个值。第一个参数(我们称为字符串)是所有纯字符串(任何内插表达式之间的内容)的数组。

然后,我们使用()将所有后续参数收集到称为值的数组中... gather/rest operator,尽管您当然可以像上面那样在字符串参数之后将它们保留为单独的命名参数(value1, value2 etc)

function myTaggedLiteral(strings,...values) {
  console.log(strings);
  console.log(values);    
}

let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]

argument(s)收集到我们的价值观数组是在字符串字面发现已经评价插值表达式的结果。tagged string literal在评估插值之后但在编译最终的字符串值之前,A就像一个处理步骤,使您可以更好地控制从文字生成字符串。让我们来看一个创建的示例re-usable templates

const Actor = {
  name: "RajiniKanth",
  store: "Landmark"
}

const ActorTemplate = templater`<article>
  <h3>${'name'} is a Actor</h3>
  <p>You can find his movies at ${'store'}.</p>

</article>`;

function templater(strings, ...keys) {
  return function(data) {
  let temp = strings.slice();
  keys.forEach((key, i) => {
  temp[i] = temp[i] + data[key];
  });
  return temp.join('');
  }
};

const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);

原始字符串

我们的标签功能接收称为第一个参数我们strings,这是一个array。但是其中还包含其他数据:所有字符串的原始未处理版本。您可以使用.raw属性访问这些原始字符串值,如下所示:

function showraw(strings, ...values) {
 console.log( strings );
 console.log( strings.raw );
}
showraw`Hello\nWorld`;

如您所见,raw字符串的版本保留转义的\ n序列,而字符串的已处理版本将其视为未转义的真实换行符。 ES6带有一个内置函数,可用作字符串文字标签: String.raw(..)。它只是通过的原始版本strings

console.log( `Hello\nWorld` );
/* "Hello
World" */

console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"

4

它更清洁,并且如注释中所述,是另一种语言的常用功能。我发现不错的另一件事是换行符,在编写字符串时非常有用。

let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };

let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
                   "<p>I am " + person.age + " old</p>\n" +
                   "<strong>\"" + person.greeting +"\" is what I usually say</strong>";


let newHtmlStr = 
 `<p>My name is ${person.name},</p>
  <p>I am ${person.age} old</p>
  <p>"${person.greeting}" is what I usually say</strong>`;


console.log(usualHtmlStr);
console.log(newHtmlStr);

我不明白在字符串和文字中使用换行符是否有重大区别。检查此es6fiddle.net/i3vj1ldl。文字仅放置空格而不是换行符
Naeem Shaikh 2014年

1
哇,我没有说这是一个很大的不同。文字换行符只是语法糖。仅出于可读性考虑。
Rigotti 2014年

但您仍然指出了很大的不同。但是在接受您的答案之前,我将等待更多时间以给出更好的答案,该答案显示出很大的不同(如果有的话!):)
Naeem Shaikh 2014年

2
@NaeemShaikh我非常抱歉,但文字换行符确实有效。刚刚注意到,ES6Fiddle只是测试它的一种糟糕方法。我将编辑答案。
Rigotti 2014年

2

一会儿,我的回答并没有直接解决这个问题。我认为指出使用模板文字支持数组连接的一个缺点可能会引起一些兴趣。

可以说我有

let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};

因此,有些患者有一个MiddleName,而另一些则没有。

如果我想要一个代表患者全名的字符串

let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;

然后,这将成为“约翰不确定史密斯”

但是如果我做到了

let patientName = [patient1.firstName, patient1.middleName,  patient1.lastName].join(" ");

然后就变成了“约翰·史密斯”

编辑

General_Twyckenham指出,对“”的连接会在“ John”和“ Smith”之间产生多余的空间。

为了解决这个问题,您可以在联接之前使用过滤器来摆脱虚假值: [patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");


2
实际上,这不是很正确-join版本将为您提供John Smith的额外空间。可以想象,这通常是不可取的。为此,可以使用map如下解决方法:[patient1.firstName, patient1.middleName, patient1.lastName].map(el => el).join(" ");
General_Twyckenham

@General_Twyckenham啊,我明白你的意思了。接得好。另外,它应该是过滤器,而不是映射器以消除多余的空间。谢谢,我将编辑我的答案。
Dhruv Prakash

糟糕-是的,这filter就是我的意思。
General_Twyckenham

并且根据此讨论,字符串连接比数组连接要快。stackoverflow.com/questions/7299010/...
迈克尔·哈雷
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.