ES6 模板字面量与连接字符串

IT技术 javascript node.js ecmascript-6 template-strings
2021-01-30 09:49:36

我有以下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}.`;

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

我已经能够将字符串MyVarperson.name此处连接起来,那么使用模板文字的场景是什么?

4个回答

如果您`Hello ${person.name}`在问题示例中仅使用带有占位符(例如)的模板文字,则结果与仅连接字符串相同。主观上它看起来更好并且更容易阅读,特别是对于多行字符串或包含两者的字符串'"因为您不必再​​转义这些字符。

可读性是一个很棒的特性,但关于模板最有趣的事情是标记模板文字

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}/']`
好的!如果您在那里有另一个模板文字,例如 ${person.message},它会被一起翻译吗?
2021-03-19 09:49:36
我尝试a.${className}[href=~'//${domain}/']在 chrome 控制台中运行 $ (并在之前设置className=''domain=''但我没有得到 DOM 节点而是字符串数组:/(在另一个没有,在 jsfiddle 中,我们在控制台中得到错误:jsfiddle.net/d1fkta76 “未捕获的 ReferenceError : $ 未定义” - 为什么?
2021-03-19 09:49:36
@AniketSuryavanshi 这是模板字符串与连接性能的比较:stackoverflow.com/a/29083467/897024几年前模板字符串速度较慢,但​​现在看起来它们比连接快一点。
2021-03-23 09:49:36
@Rigotti 这取决于msg函数的实现您当然也可以翻译替换值。
2021-03-24 09:49:36
@Beat 整个 ecmascript.org 站点似乎都关闭了。我认为他们无论如何都计划放弃他们的维基,所以我已经用存档版本更新了链接。
2021-03-25 09:49:36

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!

在这里,与"s"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这里使用运算符来传递多个值。第一个参数——我们称之为字符串——是一个包含所有普通字符串(任何内插表达式之间的内容)的数组。

然后,我们使用 将所有后续参数收集到一个名为 values 的数组中... 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)收集到我们的value观数组是在字符串字面发现已经评价插值表达式的结果。Atagged 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 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);
哦,我没有说这是一个重大差异。文字换行符只是语法糖。这只是为了可读性。
2021-03-20 09:49:36
但你仍然指出了一个很好的区别。但在接受您的答案之前,我会再等一段时间以获得更好的答案,该答案显示出任何重大差异(如果有的话!):)
2021-03-22 09:49:36
@NaeemShaikh 我非常抱歉,但文字换行符确实有效。刚刚注意到 ES6Fiddle 只是一种糟糕的测试方式。我会编辑我的答案。
2021-03-31 09:49:36
我不明白在字符串和文字中换行是否有重大区别。检查这个es6fiddle.net/i3vj1ldl文字只放一个空格而不是换行符
2021-04-10 09:49:36

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

假设我有

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

所以有些患者有一个中间名,而另一些则没有。

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

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

然后这将成为“John undefined Smith”

但是,如果我这样做了

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

然后这将变成只是“约翰史密斯”

General_Twyckenham 指出“”上的连接会导致“John”和“Smith”之间出现额外的空格。

为了解决这个问题,您可以在加入之前使用过滤器来去除虚假值:

[patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");
oop - 是的,这filter就是我的意思。
2021-03-20 09:49:36
实际上,这并不完全正确 - 该join版本将为您提供John Smith,并带有额外的空间。可以想象,这通常是不可取的。对此的解决方法是map像这样使用[patient1.firstName, patient1.middleName, patient1.lastName].map(el => el).join(" ");
2021-03-26 09:49:36
@General_Twyckenham 啊,我明白你的意思。接得好。此外,它应该是过滤器而不是映射来摆脱多余的空间。我会编辑我的答案,谢谢。
2021-03-26 09:49:36
根据这个讨论,字符串连接比数组连接更快。stackoverflow.com/questions/7299010/...
2021-03-31 09:49:36