[javascript] ES6 템플릿 리터럴을 런타임에 대체 (또는 재사용) 할 수 있습니까?

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!

expletiveis 선언되지 않았기 때문에 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-templatenpm모듈 이이를 수행합니다.

const fillTemplate = require('es6-dynamic-template');

현재 답변과 달리 :

  • 유사한 형식이 아닌 ES6 템플릿 문자열을 사용합니다. 업데이트 버전 2는 ES6 템플릿 문자열이 아닌 유사한 형식을 사용하여 사용자가 비정상적인 입력 문자열을 사용하는 것을 방지합니다.
  • this템플릿 문자열에 필요하지 않습니다.
  • 단일 함수에서 템플릿 문자열 및 변수를 지정할 수 있습니다.
  • StackOverflow의 copypasta가 아닌 유지 관리되고 업데이트 가능한 모듈입니다.

사용법은 간단합니다. 나중에 해결 될 템플릿 문자열로 작은 따옴표를 사용하십시오!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});


답변

예, Function(또는 eval)에 의해 JS로 템플릿을 사용하여 문자열을 구문 분석하여 수행 할 수 있습니다. 그러나 이것은 권장되지 않으며 XSS 공격을 허용 합니다.

대신 다음과 같이 동적 방식으로 템플릿 에 개체 필드를 안전하게 삽입 할 수 있습니다.objstr

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