javascript - literales de plantilla ES6 vs. cadenas concatenadas
Tengo el siguiente código para literales de plantilla de 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);
La salida es la siguiente:
template literal= My name is John Smith.
my variable = My name is John Smith.
Este es el violín.
Intenté buscar la diferencia exacta, pero no pude encontrarla. ¿Cuál es la diferencia entre las siguientes dos declaraciones?
let tpl = `My name is ${person.name}.`;
Y
let MyVar = "My name is "+ person.name+".";
Ya puedo obtener la cadena MyVar concatenada con person.name aquí, entonces ¿cuál sería el escenario para usar la plantilla literal?
Respuesta #1
Si estás usando literales de plantilla solo con marcadores de posición (por ejemplo, `Hello $ {person.name}`) como en el ejemplo de la pregunta, entonces el resultado es el mismo que simplemente concatenar cadenas. Subjetivamente se ve mejor y es más fácil de leer, especialmente para cadenas de varias líneas o cadenas que contienen tanto ' como ", ya que ya no tienes que escapar esos caracteres.
La legibilidad es una gran característica, pero lo más interesante de las plantillas son los literales de plantilla etiquetados:
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!
En la tercera línea de este ejemplo, se llama a una función llamada tag. El contenido de la cadena de plantilla se divide en múltiples variables, a las que puedes acceder en los argumentos de la función tag: secciones literales (en este ejemplo, el valor de strArr[0] es My name is y el valor de strArr[1] es !) y sustituciones (John Smith). La cadena de plantilla se evaluará según lo que devuelva la función tag.
El wiki de ECMAScript enumera algunos posibles casos de uso, como escapar o codificar automáticamente la entrada, o la localización. Podrías crear una función de etiqueta llamada msg que busque las partes literales como My name is y las sustituya con traducciones al idioma de la configuración regional actual, por ejemplo, al alemán:
console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.
El valor devuelto por la función de etiqueta ni siquiera tiene que ser una cadena. Podrías crear una función de etiqueta llamada $ que evalúe la cadena y la use como un selector de consulta para devolver una colección de nodos del DOM, como en este ejemplo:
$`a.${className}[href=~'//${domain}/']`
Respuesta #2
ES6 introduce un nuevo tipo de literal de cadena, usando el ` back-tick como delimitador. Estos literales permiten que se incorporen expresiones básicas de interpolación de cadenas, las cuales son luego analizadas y evaluadas automáticamente.
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);
Como puedes ver, usamos los ..`` alrededor de una serie de caracteres, que se interpretan como un literal de cadena, pero cualquier expresión de la forma $ {..} se analiza y evalúa en línea inmediatamente.
Un beneficio realmente bueno de los literales de cadena interpolados es que se les permite dividirse en varias líneas:
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!
Expresiones Interpoladas
Cualquier expresión válida puede aparecer dentro de $ {..} en un literal de cadena interpolada, ¡incluyendo llamadas a funciones, llamadas a expresiones de funciones en línea e incluso otros literales de cadena interpolada!
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!
Aquí, el literal de cadena interpolada inner $ {who}s`` fue una pequeña comodidad para nosotros al combinar la variable who con la cadena "s", en lugar de who + "s". También hay que tener en cuenta que un literal de cadena interpolada está simplemente lexically scoped donde aparece, no dynamically scoped de ninguna manera:
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!"
Usar el template literal para el HTML es definitivamente más legible al reducir las molestias.
La manera sencilla y tradicional:
'<div class="' + className + '">' +
'<p>' + content + '</p>' +
'<a href="' + link + '">Let\'s go</a>'
'</div>';
Con ES6:
`<div class="${className}">
<p>${content}</p>
<a href="${link}">Let's go</a>
</div>`
- Tu cadena puede abarcar varias líneas.
- No tienes que escapar los caracteres de comillas.
- Puedes evitar agrupaciones como: '">
- No tienes que usar el operador más.
Literales de Plantilla Etiquetadas
También podemos etiquetar una cadena template, cuando una cadena template es etiquetada, los literals y las sustituciones se pasan a una función que devuelve el valor resultante.
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
Podemos usar el operador spread aquí para pasar múltiples valores. El primer argumento — lo llamamos strings — es un arreglo de todas las cadenas simples (las cosas entre cualquier expresión interpolada).
luego reunimos todos los argumentos posteriores en un array llamado values usando el operador ... gather/rest, aunque por supuesto podrías haberlos dejado como parámetros individuales nombrados siguiendo el parámetro de strings como hicimos arriba (value1, value2, etc).
function myTaggedLiteral(strings,...values) {
console.log(strings);
console.log(values);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]
Los argumentos recogidos en nuestro array de valores son los resultados de las expresiones de interpolación ya evaluadas que se encuentran en el literal de cadena. Un literal de cadena etiquetado es como un paso de procesamiento después de que se evalúan las interpolaciones pero antes de que se compile el valor final de la cadena, lo que te permite tener más control sobre la generación de la cadena a partir del literal. Veamos un ejemplo de cómo crear plantillas reutilizables.
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);
Cadenas sin procesar
Nuestras funciones de etiquetas reciben un primer argumento que llamamos strings, que es un array. Pero hay un dato adicional incluido: las versiones sin procesar de todas las cadenas. Puedes acceder a esos valores de cadena sin procesar usando la propiedad .raw, así:
function showraw(strings, ...values) {
console.log( strings );
console.log( strings.raw );
}
showraw`Hello\nWorld`;
Como puedes ver, la versión raw de la cadena conserva la secuencia escapada \n, mientras que la versión procesada de la cadena la trata como un salto de línea real no escapado. ES6 viene con una función incorporada que se puede usar como una etiqueta de literal de cadena: String.raw(..). Simplemente pasa las versiones raw de las cadenas:
console.log( `Hello\nWorld` );
/* "Hello
World" */
console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"
