Poznajemy tagged template literals w JavaScript – mało znaną, ale potężną i niedocenianą właściwość tego języka. Do dzieła.
Ok, mały przykład jak to działa:
function tagged1(strings){
console.log(strings);
}
tagged1`Hello World 123 !`;
//[ "Hello World 123 !" ]
tagged1`Hello World ${2+2} Hi yolo`;
//[ "Hello World ", " Hi yolo" ]
Po pierwsze – tak, to działa. Po drugie, w strings lądują elementy tekstowe niebędące wyrażeniem. Jeżeli nie ma wyrażeń, to cały string jako tablica jednoelementowa tam jest.
Ok, a co z wyrażeniami? Możemy je zbierać pojedynczo, ale ja wolę też je do tablicy zapakować:
function tagged2(strings, ...expr){
console.log(strings);
console.log(expr);
}
tagged2`Hello World ${2+2} Hi yolo`;
//[ "Hello World ", " Hi yolo" ]
//Array [ 4 ]
Teraz do czego nam to. W internecie znalazłem taką funkcję:
function highlight(strings, ...values) {
let str = '';
strings.forEach((string, i) => {
str += string + values[i];
});
return str;
}
Niby fajnie, tylko tu robimy dwa założenia:
- Wyrażenie nigdy nie będzie przed napisem
- Ilość wyrażeń i napisów będzie równa
Ok, sprawdźmy to pierwsze, czyli co się dzieje gdy dodamy wyrażenie przed napisem:
function tagged2(strings, ...expr){
console.log(strings);
console.log(expr);
}
tagged2`${2+2}Hello World ${2+2} Hi yolo`;
//[ "", "Hello World ", " Hi yolo" ]
//Array [ 4, 4 ]
No to akurat nie problem jak widać – strings po prostu zaczną się od pustego napisu. Jest to o tyle dobre, że kolejność dodawania mamy taką, że najpierw string, potem expr i nie chcemy, by cokolwiek ją popsuło.
Ale w przykładzie poprzednim widzieliśmy, że napisów może być więcej niż wyrażeń. Tutaj też widzimy, mamy pusty „” i dwa napisy, razem trzy, zaś wyrażenia tylko 2.
Tu już jest lepszy przykład (od tego samego autora):
function highlight(strings, ...values) {
let str = '';
strings.forEach((string, i) => {
str += `${string} <span class='hl'>${values[i] || ''}</span>`;
});
return str;
}
Natomiast ten kod będzie puste spany produkował. Inny przykład od tego autora:
function highlight(strings, ...values) {
let str = '';
strings.forEach((string, i) => {
str += string + (values[i] || '');
});
return str;
}
To już jest dobry trop. Cóż, po coś my te replacementy zbieramy i pakujemy do jednej tablicy. Możemy na niej użyć np. map:
function highlight(strings, ...expr){
let str = "";
let highlightedExpr = expr.map((el) => `<strong>${el}</strong>`);
strings.forEach((string, i) => {
str += string + (highlightedExpr[i] || '');
});
return str;
}
let highlighted = highlight`Hello World ${2+2} Hi yolo`;
console.log(highlighted);
//Hello World <strong>4</strong> Hi yolo
I tu mamy takie coś, co niezależnie od tego czy liczba tekstów pokrojonych wyrażeniami i replacementów się zgadza czy nie poskleja wszystko do kupy, zaś replacementy będą w tagu strong.
Przeanalizujmy to sobie na spokojnie, bo nie jest to łatwe.