tl; dr : 재사용 가능한 템플릿을 리터럴로 만들 수 있습니까?
템플릿 리터럴을 사용하려고했지만 이해가 안되는 것 같고 이제 좌절감을 느끼고 있습니다. 내 말은, 나는 그것을 얻는다고 생각하지만 “그것”은 그것이 어떻게 작동하는지, 어떻게 얻어야 하는가가 아니어야합니다. 달라져야합니다.
내가 본 모든 예제 (심지어 태그가있는 템플릿)는 “대체”를 런타임이 아닌 선언 시간에 수행해야하는데, 이는 템플릿에 대해 전혀 쓸모가 없어 보입니다. 내가 미쳤을 수도 있지만, “템플릿”은 토큰을 만들 때가 아니라 사용할 때 대체되는 토큰을 포함하는 문서입니다. 그렇지 않으면 문서 (예 : 문자열) 일뿐입니다. 템플릿은 토큰 과 함께 토큰 과 함께 저장되며 해당 토큰은 평가할 때 평가됩니다.
누구나 다음과 같은 끔찍한 예를 인용합니다.
var a = 'asd';
return `Worthless ${a}!`
멋지지만 이미 알고 있다면 a
그냥 return 'Worthless asd'
또는 return 'Worthless '+a
. 점은 무엇인가? 진지하게. 좋아요 요점은 게으름입니다. 더 적은 장점, 더 많은 가독성. 큰. 그러나 그것은 템플릿이 아닙니다! IMHO가 아닙니다. 그리고 MHO가 중요합니다! 문제인 IMHO는 템플릿이 선언 될 때 평가된다는 것입니다. 따라서 그렇게한다면 IMHO는 다음과 같습니다.
var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!
expletive
is 선언되지 않았기 때문에 My undefined template
. 감독자. 사실, 적어도 Chrome에서는 템플릿을 선언 할 수도 없습니다. expletive
정의되지 않았기 때문에 오류가 발생 합니다. 내가 필요한 것은 템플릿을 선언 한 후 대체를 수행 할 수있는 것입니다.
var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template
그러나 이것이 실제로 템플릿이 아니기 때문에 이것이 어떻게 가능한지 모르겠습니다. 태그를 사용해야한다고해도 작동하지 않습니다.
> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...
이 모든 것이 템플릿 리터럴의 이름이 끔찍하게 잘못되어 실제 이름으로 불러야한다고 믿게 만들었습니다 : heredocs . 나는 “문자 그대로”부분이 나에게 팁을 주었어야한다고 생각한다.
내가 뭔가를 놓치고 있습니까? 재사용 가능한 템플릿을 리터럴로 만드는 (좋은) 방법이 있습니까?
재사용 가능한 템플릿 리터럴을 제공합니다 .
> function out(t) { console.log(eval(t)); }
var template = `\`This is
my \${expletive} reusable
template!\``;
out(template);
var expletive = 'curious';
out(template);
var expletive = 'AMAZING';
out(template);
< This is
my undefined reusable
template!
This is
my curious reusable
template!
This is
my AMAZING reusable
template!
그리고 여기에 순진한 “도우미”기능이 있습니다 …
function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);
… “더 좋게”만들기 위해.
나는 그것들이 구불 구불 한 느낌을 생성하는 영역 때문에 템플릿 구 테랄이라고 부르는 경향이 있습니다.
답변
이러한 리터럴이 다른 템플릿 엔진처럼 작동하도록하려면 중개 양식이 필요합니다.
이를 수행하는 가장 좋은 방법은 Function
생성자 를 사용하는 것 입니다.
const templateString = "Hello ${this.name}!";
const templateVars = {
name: "world"
}
const fillTemplate = function(templateString, templateVars){
return new Function("return `"+templateString +"`;").call(templateVars);
}
console.log(fillTemplate(templateString, templateVars));
다른 템플릿 엔진과 마찬가지로 파일과 같은 다른 위치에서 해당 문자열을 가져올 수 있습니다.
템플릿 태그를 사용하기 어려운 것처럼이 방법을 사용하는 데 문제가있을 수 있지만 영리하다면 추가 할 수 있습니다. 또한 늦은 보간으로 인해 인라인 JavaScript 로직을 가질 수 없습니다. 이것은 또한 약간의 생각으로 해결할 수 있습니다.
답변
함수에 템플릿 문자열을 넣을 수 있습니다.
function reusable(a, b) {
return `a is ${a} and b is ${b}`;
}
태그가 지정된 템플릿으로 동일한 작업을 수행 할 수 있습니다.
function reusable(strings) {
return function(... vals) {
return strings.map(function(s, i) {
return `${s}${vals[i] || ""}`;
}).join("");
};
}
var tagged = reusable`a is ${0} and b is ${1}`; // dummy "parameters"
console.log(tagged("hello", "world"));
// prints "a is hello b is world"
console.log(tagged("mars", "jupiter"));
// prints "a is mars b is jupiter"
아이디어는 템플릿 파서가 변수 “slots”에서 상수 문자열을 분리 한 다음 매번 새로운 값 집합을 기반으로 다시 함께 패치하는 함수를 반환하는 것입니다.
답변
아마도이 작업을 수행하는 가장 깨끗한 방법은 화살표 함수를 사용하는 것입니다 (이 시점에서는 이미 ES6를 사용하고 있기 때문입니다).
var reusable = () => `This ${object} was created by ${creator}`;
var object = "template string", creator = "a function";
console.log (reusable()); // "This template string was created by a function"
object = "example", creator = "me";
console.log (reusable()); // "This example was created by me"
… 태그가 지정된 템플릿 리터럴의 경우 :
reusable = () => myTag`The ${noun} go ${verb} and `;
var noun = "wheels on the bus", verb = "round";
var myTag = function (strings, noun, verb) {
return strings[0] + noun + strings[1] + verb + strings[2] + verb;
};
console.log (reusable()); // "The wheels on the bus go round and round"
noun = "racecars", verb = "fast";
myTag = function (strings, noun, verb) {
return strings[0] + noun + strings[1] + verb;
};
console.log (reusable()); // "The racecars go fast"
이것은 또한 컴파일러에 문제를 일으키고 많은 속도 저하를 유발할 수있는 eval()
or 의 사용을 피합니다 Function()
.
답변
2019 답변 :
참고 : 라이브러리는 원래 사용자가 XSS를 피하기 위해 문자열을 삭제해야한다고 예상했습니다. 라이브러리의 버전 2는 eval
완전히 피하므로 더 이상 사용자 문자열을 삭제 (웹 개발자가 수행해야하는 작업) 할 필요가 없습니다.
es6-dynamic-template
npm 의 모듈 이이를 수행합니다.
const fillTemplate = require('es6-dynamic-template');
현재 답변과 달리 :
- 유사한 형식이 아닌 ES6 템플릿 문자열을 사용합니다. 업데이트 버전 2는 ES6 템플릿 문자열이 아닌 유사한 형식을 사용하여 사용자가 비정상적인 입력 문자열을 사용하는 것을 방지합니다.
this
템플릿 문자열에 필요하지 않습니다.- 단일 함수에서 템플릿 문자열 및 변수를 지정할 수 있습니다.
- StackOverflow의 copypasta가 아닌 유지 관리되고 업데이트 가능한 모듈입니다.
사용법은 간단합니다. 나중에 해결 될 템플릿 문자열로 작은 따옴표를 사용하십시오!
const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});
답변
예, Function
(또는 eval
)에 의해 JS로 템플릿을 사용하여 문자열을 구문 분석하여 수행 할 수 있습니다. 그러나 이것은 권장되지 않으며 XSS 공격을 허용 합니다.
대신 다음과 같이 동적 방식으로 템플릿 에 개체 필드를 안전하게 삽입 할 수 있습니다.obj
str
let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
답변
@metamorphasi에서 제공하는 답변을 단순화합니다.
const fillTemplate = function(templateString, templateVars){
var func = new Function(...Object.keys(templateVars), "return `"+templateString +"`;")
return func(...Object.values(templateVars));
}
// Sample
var hosting = "overview/id/d:${Id}";
var domain = {Id:1234, User:22};
var result = fillTemplate(hosting, domain);
console.log(result);
답변
당신이 당신의 템플릿에서 변수를 참조하도록 명령 매개 변수 또는 컨텍스트 / 네임 스페이스를 사용하지 않으려면 예를 들어 ${0}
, ${this.something}
또는 ${data.something}
, 당신은 당신을위한 범위 지정을 담당 템플릿 기능을 가질 수있다.
이러한 템플릿을 호출하는 방법의 예 :
const tempGreet = Template(() => `
<span>Hello, ${name}!</span>
`);
tempGreet({name: 'Brian'}); // returns "<span>Hello, Brian!</span>"
템플릿 기능 :
function Template(cb) {
return function(data) {
const dataKeys = [];
const dataVals = [];
for (let key in data) {
dataKeys.push(key);
dataVals.push(data[key]);
}
let func = new Function(...dataKeys, 'return (' + cb + ')();');
return func(...dataVals);
}
}
이 경우 특이한 점은 ES6 템플릿 리터럴을 반환하는 함수 (예에서는 화살표 함수를 사용함)를 전달해야한다는 것입니다. 우리가 추구하는 재사용 가능한 보간을 얻는 것은 사소한 절충안이라고 생각합니다.
여기 GitHub에 있습니다 : https://github.com/Adelphos/ES6-Reuseable-Template