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

5
Не знаєте, що ви маєте на увазі під "різницею", як tpl === MyVar? Різниця лише в синтаксисі, з яким вони були створені. Зверніть увагу, що шаблони, на відміну від конкатенації рядків, також забезпечують функції тегів, які можна використовувати для таких речей, як автоматичне екранування.
Бергі

Ви в основному запитуєте, яка різниця між інтерполяцією рядків та конкатенацією рядків.
Damjan Pavlica

Відповіді:


104

Якщо ви використовуєте літерали шаблонів лише із заповнювачами (наприклад `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]є My name isі значення strArr[1]є !) та заміни ( 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}, він би був перекладений?
Ріготті

1
@Rigotti Це залежить від реалізації msgфункції. Ви, звичайно, також можете перекласти значення заміщення.
kapex

@Beat Весь сайт ecmascript.org, здається, не працює. Я думаю, що вони все-таки планували відмовитися від своєї вікі, тому я оновив посилання заархівованими версіями.
kapex

Я намагаюсь запустити $ a.${className}[href=~'//${domain}/']в консолі chrome (і встановити до className=''і, domain=''але я не отримую вузли DOM, а масив рядків: / (в іншому hadn, в jsfiddle ми отримуємо помилку в консолі: jsfiddle.net/d1fkta76 "Uncaught ReferenceError : $ не визначено "- чому?
Каміль Kiełczewski

2
@AniketSuryavanshi Ось порівняння рядків шаблонів та продуктивності конкатенації: stackoverflow.com/a/29083467/897024 Кілька років тому рядки шаблонів були повільнішими, але схоже, що вони трохи швидші, ніж конкатенація зараз.
kapex

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 literalHTML для 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, хоча, звичайно, ви могли б залишити їх як окремі іменовані параметри, слідуючи параметру рядків, як це було зроблено вище (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)Зібрані в нашій цінності масиву результати вже оцінених інтерполяційних виразів , знайдених в строковий літерал. A 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"

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

1
Ого, я не сказав, що це велика різниця. Літеральні розриви - це просто синтаксичний цукор. Це просто для читабельності.
Ріготті,

але ви все-таки вказали на хорошу різницю. але перед тим, як прийняти вашу відповідь, я почекаю ще деякий час, щоб отримати кращу відповідь, яка показує велику різницю (якщо така є!) :)
Naeem Shaikh

2
@NaeemShaikh Мені страшенно шкода, але буквальні розриви рядків насправді працюють. Щойно помітив, що ES6Fiddle - це просто жахливий спосіб перевірити його. Я відредагую свою відповідь.
Ріготті

2

Поки моя відповідь не стосується безпосередньо питання. Я вважав, що може бути цікавим вказати на один недолік використання літералів шаблонів на користь об’єднання масиву.

Скажімо, я маю

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

Тоді це стане просто "Джон Сміт"

РЕДАГУВАТИ

General_Twyckenham зазначив, що приєднання до "" призведе до додаткового простору між "Джоном" та "Смітом".

Для того, щоб обійти це, ви можете мати фільтр перед об'єднанням, щоб позбутися помилкових значень: [patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");


2
Насправді це не зовсім правильно - joinверсія дасть вам Джона Сміта з додатковим простором. Як ви можете собі уявити, це часто небажано. Виправлення для цього полягає у використанні mapтаким чином:[patient1.firstName, patient1.middleName, patient1.lastName].map(el => el).join(" ");
General_Twyckenham

@General_Twyckenham aah Я бачу вашу думку. Хороший улов. Крім того, він повинен бути фільтром, а не картою, щоб позбутися цього зайвого місця. Я відредагую свою відповідь, дякую.
Дхрюв Пракаш

Уфс - так, це filterбула функція, яку я мав на увазі.
General_Twyckenham

І згідно з цим обговоренням, об’єднання рядків відбувається швидше, ніж об’єднання масиву. stackoverflow.com/questions/7299010/…
Майкл Харлі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.