ES6模板文字与连接字符串

我有以下 ECMAScript 6 模板文字的代码:

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}.`;

And

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

我已经能够在这里获得与 person.name连接的字符串 MyVar,那么在什么场景中使用模板文字呢?

118829 次浏览

它干净多了,正如评论中所说,这是另一种语言的一个共同特性。 另一件我觉得不错的事情是换行符,在编写字符串时非常有用。

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

如果你只在占位符中使用模板文字(例如 `Hello ${person.name}`) ,就像问题的例子一样,那么结果和串联字符串是一样的。主观上,它看起来更好,更容易阅读,特别是对于包含 '"的多行字符串或字符串,因为您不再需要转义这些字符。

Readability is a great feature, but the most interesting thing about templates are 标记的模板文字:

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]的值是 My name is strArr[1]的值是 !)和替换(John Smith)。模板文字将被计算为 tag函数返回的任何值。

ECMAScript wiki列出了一些可能的用例,比如自动转义、编码输入或本地化。您可以创建一个名为 msg的标记函数,该函数查找像 My name is 这样的文字部分,并将它们替换为当前语言环境的翻译,例如翻译成德语:

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

标记函数返回的值甚至不必是字符串。您可以创建一个名为 $的标记函数,该函数计算字符串并将其用作查询选择器,以返回一组 DOM 节点,如下面的 例子所示:

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

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 }的“内插字符串文字”在将 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字符串,当标记一个 template字符串时,literals和替换被传递给返回结果值的函数。

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将所有后续参数收集到一个名为 value 的数组中,当然,您可以像上面的 (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类似于计算插值之后但在编译最终字符串值之前的处理步骤,允许您更多地控制从文字生成字符串。让我们看一个创建 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"

虽然我的回答并没有直接回答这个问题,但是我认为指出使用模板文字有利于数组连接的一个缺点可能会引起一些兴趣。

就算是吧

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

所以有些病人有中间名,有些没有。

如果我想要一个表示病人全名的字符串

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

那么这就变成了 “未定义的约翰・史密斯”

如果我做了呢

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

Then this would become just “约翰・史密斯”

General _ Twyckenham 指出,“ on”的连接将导致“ John”和“ Smith”之间多出一个空格。

To get around this, you can have a filter before the join to get rid of falsy values:

[patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");