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


129

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!`);

... "더 좋게"만들기 위해.

나는 그것들이 구불 구불 한 느낌을 생성하는 영역 때문에 템플릿 구 테랄이라고 부르는 경향이 있습니다.


1
취소 선은 지원하지만 이와 같은 주석에서는 지원하지 않습니다. <strike>태그에 텍스트를 넣으십시오 .
Pointy

ES6 템플릿 리터럴은 대부분 구식 문자열 보간 용입니다. 동적 템플릿을 원하는 경우 Handlebars 등 또는 Pointy의 태그가 지정된 템플릿 솔루션을 사용하십시오.
joews

1
템플릿 문자열은 이름에도 불구하고 템플릿이 없습니다 . 참조 ES6 템플릿 문자열에 대한 연기 실행
BERGI

8
당신의 게시물을 좀 덜 비싸게 만들 수 있습니까? 또한 Q & A 형식으로 튜토리얼을 작성하려는 것 같습니다. 그렇게 했다면 질문 에서 " I give you… "부분을 제거하고 답변 으로 게시 하세요 .
Bergi

여기에 좋은 답변이 많이 있습니다. 아마도 하나를 받아들이십시오.
abalter

답변:


86

이러한 리터럴이 다른 템플릿 엔진처럼 작동하도록하려면 중개 양식이 필요합니다.

이를 수행하는 가장 좋은 방법은 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 로직을 가질 수 없습니다. 이것은 또한 약간의 생각으로 해결할 수 있습니다.


8
좋은! 당신은 사용할 수 있습니다new Function(`return \`${template}\`;`)
루벤 Stolk

그리고 이러한 템플릿은 메서드를 호출하거나 다른 템플릿의 컴파일 된 결과를 전달하여 인수를 통해 구성하거나 "포함"할 수 있습니다.
Quentin Engles

Quentin '템플릿 태그 없음'은 무엇을 의미합니까? 감사!
mikemaccana

10
조심 이 템플릿 문자열이 좀 뭔가로하지 transpile 따라서 것 transpilation에 '숨겨진'(즉, 웹팩) 것을 (즉, IE11) 충분히 호환 클라이언트 측에 ...!
Frank Nocke


65

함수에 템플릿 문자열을 넣을 수 있습니다.

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"에서 상수 문자열을 분리 한 다음 매번 새로운 값 집합을 기반으로 다시 함께 패치하는 함수를 반환하는 것입니다.


3
@FelixKling 일 수 있습니다; 그렇다면 확인하고 수정하겠습니다. edit yes "재사용 가능"기능인 예제의 상당 부분을 생략 한 것 같습니다. :)
Pointy

@FelixKling 그 당시 생각했던 것을 전혀 기억할 수 없기 때문에 무엇을 해야할지 모르겠습니다!
Pointy

1
당신은 항상 그것을 제거 할 수 있습니다 ....하지만) 네, TBH이 될 훨씬 이해가되지 않습니다 reusable그래서 함수를 반환 구현 될 수 있으며, 당신이 사용하는 거라고 ${0}${1}대신 문자 내부 ${a}${b}. 그런 다음 해당 값을 사용하여 Bergi의 마지막 예제 인 stackoverflow.com/a/22619256/218196 (또는 기본적으로 동일 함)에서 수행 한 것과 유사한 함수의 인수를 참조 할 수 있습니다 .
Felix Kling

1
@FelixKling OK 나는 OP의 라인을 따라 적어도 모호한 무언가를 생각해 낸 것 같습니다.
Pointy

3
결과가 실제로 문자열이 아닌 경우 태그가있는 템플릿은 정말 강력 할 수 있습니다. 예를 들어 내 프로젝트 중 하나에서 AST 노드 보간을 수행하는 데 사용합니다. 예를 들어 expression`a + ${node}`기존 AST 노드로 BinaryExpression 노드를 구축 할 수 있습니다 node. 내부적으로 자리 표시자를 삽입하여 유효한 코드를 생성하고 AST로 구문 분석하고 자리 표시자를 전달 된 값으로 바꿉니다.
펠릭스 클링

45

아마도이 작업을 수행하는 가장 깨끗한 방법은 화살표 함수를 사용하는 것입니다 (이 시점에서는 이미 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().


함수 내부에 일부 코드를 삽입 myTag하여 작업을 수행 할 수 있기 때문에 이것이 최고라고 생각합니다 . 예를 들어 입력 매개 변수를 키로 사용하여 출력을 캐시합니다.
WOW

이것이 최선의 답이라고 생각합니다. 화살표 함수에 매개 변수를 추가하여 더 깔끔하게 만들 수도 var reusable = (value: string) => `Value is ${value}`있습니다.
haggisandchips

13

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'});

React Native와 함께 사용하는 경우 특히 Android에서 중단됩니다. 안드로이드 노드 런타임 동적 템플릿 만 채워져 사람을 지원하지 않습니다
올리버 딕슨에게

1
이것은 내 개인 프로젝트에서 사용하는 솔루션이며 완벽하게 작동합니다. 특히 이와 같은 작은 유틸리티에 너무 많은 라이브러리를 사용하는 것은 나쁜 생각이라고 생각합니다.
Oliver Dixon


1
@kamil XSS 만 해당 a) 사용자에게 생성 기능을 제공 b) 입력 문자열을 삭제하지 마십시오. 사람들이 사용자 입력을 삭제해야한다는 경고를 추가하겠습니다.
mikemaccana

1
이것은 es6 템플릿 리터럴을 원격으로 사용하지 않습니다. 시도 10 * 20 = ${10 * 20}는 비슷한 형식이 될 수 있도록하지만, 심지어 원격으로 ES6 템플릿 리터럴 아니다
G 맨

12

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

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

let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);


이것은 내가 사용하는 방법이며 잘 작동합니다. 좋은 예! ? RegEx 도움말의 * 뒤에? 저는 RegEx 전문가는 아니지만 *는 0 개 이상을 의미하기 때문에 추측하고 있습니다 (이 경우 "more"를 원합니다), 탐욕스러운 제한이 필요하지 않습니까?
Gen1-1 19

Gen1-1 @ .*?수단 이 아닌 욕심 - 당신은 제거하면 "?"다음 잘못된 결과를 줄 것이다 니펫을
카밀 Kiełczewski

당신이 맞아요, 제 실수입니다. 템플릿에 $를 사용하지 않고 RegEx : / {(\ w *)} / g를 사용합니다. 태그에 공백이 없기 때문에. *? 또한 작동합니다. 나는 다음을 사용합니다.function taggedTemplate(template, data, matcher) { if (!template || !data) { return template; } matcher = matcher || /{(\w*)}/g; // {one or more alphanumeric characters with no spaces} return template.replace(matcher, function (match, key) { var value; try { value = data[key] } catch (e) { // } return value || ""; }); }
Gen1-1

@ Gen1-1도 중첩 된 데이터가 있습니까? 같은 data = { a: 1, b: { c:2, d:3 } }-> b.c?
muescha

1
@muescha 속성을 찾을 때까지 재귀를 사용하고 전체 데이터 개체와 중첩 된 개체를 검색하려면 다음 줄을 변경합니다. value = data [key]. 예 : codereview.stackexchange.com/questions/73714/…mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1

9

@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);


이 코드는 주요 답변보다 자명합니다. 내 최대 - 투표 :)있어
ymz

이를 통해 NodeJS에서 변수 또는 외부 파일을 템플릿으로 사용하거나 런타임에 동적으로 빌드 할 수 있습니다. 사용하지 않고 eval.
b01

XSS 취약점 ? 여기에 악성 코드 (변수 var hosting)가 있습니다.
Kamil Kiełczewski

7

당신이 당신의 템플릿에서 변수를 참조하도록 명령 매개 변수 또는 컨텍스트 / 네임 스페이스를 사용하지 않으려면 예를 들어 ${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


3
이 좋지만, 축소를 (발스, FUNC, 등) unnecessaery이며, 'CB'는 콜백 (이 완전히 동기화 코드)하지 않고, 당신은 사용할 수 있습니다 Object.values()Object.keys()
mikemaccana

3

짧은 대답은 lodash 에서 _.template을 사용하는 입니다.

// Use the ES template literal delimiter as an "interpolate" delimiter.
// Disable support by replacing the "interpolate" delimiter.
var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!'

3

내가 뭔가를 놓치고 있습니까? 재사용 가능한 템플릿을 리터럴로 만드는 [좋은] 방법이 있습니까?

어쩌면 나는 이 문제에 대한 내 솔루션은 내가 아무도 이러한 오래된 질문에 이미 쓴없는 매우 놀랐 나에게 너무 명백한 것 때문에, 뭔가가.

거의 한 줄짜리가 있습니다.

function defer([first, ...rest]) {
  return (...values) => rest.reduce((acc, str, i) => acc + values[i] + str, first);
}

그게 다야. 템플릿을 재사용하고 대체 해결을 연기하려면 다음을 수행합니다.

> t = defer`My template is: ${null} and ${null}`;
> t('simple', 'reusable');          // 'My template is: simple and reusable'
> t('obvious', 'late to the party'; // 'My template is: obvious and late to the party'
> t(null);                          // 'My template is: null and undefined'
>
> defer`Choose: ${'ignore'} / ${undefined}`(true, false); // 'Choose: true / false'

이 태그를 적용 하면 리터럴에 전달 된 모든 매개 변수를 무시 하는 'function'( a 대신)가 반환됩니다 'string'. 그런 다음 나중에 새 매개 변수로 호출 할 수 있습니다. 매개 변수에 대응하는 대체가 없으면 'undefined'.


확장 된 답변

이 간단한 코드는 작동하지만 더 정교한 동작이 필요한 경우 동일한 논리를 적용 할 수 있으며 무한한 가능성이 있습니다. 다음과 같이 할 수 있습니다.

  1. 원래 매개 변수를 사용하십시오.

구성에서 리터럴에 전달 된 원래 값을 저장하고 템플릿을 적용 할 때 창의적인 방식으로 사용할 수 있습니다. 플래그, 유형 유효성 검사기, 함수 등이 될 수 있습니다. 다음은 기본값으로 사용하는 예입니다.

    function deferWithDefaults([first, ...rest], ...defaults) {
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + (i < values.length ? values[i] : defaults[i]) + curr;
      }, first);
    }

그때:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. 템플릿 팩토리 작성 :

(템플릿 리터럴의 일부를 결합 할 때) 축소에 적용 할 수있는 사용자 지정 함수를 인수로 기대하고 사용자 지정 동작이있는 새 템플릿을 반환하는 함수에이 논리를 래핑하여 수행합니다.

    const createTemplate = fn => function (strings, ...defaults) {
      const [first, ...rest] = strings;
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + fn(values[i], defaults[i]) + curr;
      }, first);
    };

그런 다음, 예를 들어 임베디드 html, css, sql, bash를 작성할 때 매개 변수를 자동으로 이스케이프하거나 삭제하는 템플릿을 작성할 수 있습니다.

    function sqlSanitize(token, tag) {
      // this is a gross simplification, don't use in production.
      const quoteName = name => (!/^[a-z_][a-z0-9_$]*$/.test(name) ? `"${name.replace(/"/g, '""')}"` : name);
      const quoteValue = value => (typeof value == 'string' ? `'${value.replace(/'/g, "''")}'` : value);
      switch (tag) {
        case 'table':
          return quoteName(token);
        case 'columns':
          return token.map(quoteName);
        case 'row':
          return token.map(quoteValue);
        default:
          return token;
      }
    }

    const sql = createTemplate(sqlSanitize);

이 순진한 (반복합니다, 순진한! ) SQL 템플릿을 사용하여 다음과 같은 쿼리를 작성할 수 있습니다.

    > q  = sql`INSERT INTO ${'table'} (${'columns'})
    ... VALUES (${'row'});`
    > q('user', ['id', 'user name', 'is"Staff"?'], [1, "O'neil", true])
    // `INSERT INTO user (id,"user name","is""Staff""?")
    // VALUES (1,'O''neil',true);`
  1. 대체를 위해 명명 된 매개 변수 허용 : 이미 주어진 내용을 기반으로하는 그리 어렵지 않은 연습입니다. 이 다른 답변 에는 구현 있습니다.

  2. 반환 객체가 'string'다음 과 같이 동작하도록합니다 . 글쎄, 이것은 논란의 여지가 있지만 흥미로운 결과로 이어질 수 있습니다. 이 다른 답변에 표시됩니다 .

  3. 호출 사이트에서 전역 네임 스페이스 내의 매개 변수를 확인합니다.

재사용 가능한 템플릿 리터럴을 제공합니다.

음,이 무엇 영업 이익은 보여 주었다 것은 명령을 사용하여, 자신의 부록이다 evil, 내 말은 eval. 이는 eval전달 된 변수 이름을 전역 (또는 창) 객체로 검색하여를 사용 하지 않고 수행 할 수 있습니다 . 나는 그것을 좋아하지 않기 때문에 그것을하는 방법을 보여주지 않을 것입니다. 폐쇄는 올바른 선택입니다.


2

이것이 나의 최선의 시도입니다.

var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'

일반화하려면 :

var s = (<variable names you want>) => {return `<template with those variables>`}

E6를 실행하지 않는 경우 다음을 수행 할 수도 있습니다.

var s = function(<variable names you want>){return `<template with those variables>`}

이것은 이전 답변보다 약간 더 간결한 것 같습니다.

https://repl.it/@abalter/reusable-JS-template-literal


2

일반적으로 나는 악을 사용하는 것에 반대 eval()하지만이 경우에는 의미가 있습니다.

var template = "`${a}.${b}`";
var a = 1, b = 2;
var populated = eval(template);

console.log(populated);         // shows 1.2

그런 다음 값을 변경하고 eval ()을 다시 호출하면 새로운 결과가 나타납니다.

a = 3; b = 4;
populated = eval(template);

console.log(populated);         // shows 3.4

함수에서 원하면 다음과 같이 작성할 수 있습니다.

function populate(a, b){
  return `${a}.${b}`;
}

템플릿을 포함하는 함수를 작성하는 경우, 당신은 확실히 사용하지 말아야합니다 eval.
Bergi

@ Bergi 왜? 구현과 어떻게 다릅니 까?
isapir

2
내가 "알고있는 것처럼 보이는"이유는 동적으로 빌드 된 코드에 적용됩니다. eval()명시 적으로 호출하지 않고 결과를 작성하도록 함수를 작성하는 것은와 정확히 동일 eval()하므로 코드를 읽기 어렵게 만들 뿐이므로 이점이 없습니다.
isapir jul.

1
바로 그거죠. 그리고 populate함수가 코드를 동적으로 빌드하지 않기 때문에 eval모든 단점과 함께 사용해서는 안됩니다 .
Bergi

6
단지 수 함수 function populate(a,b) { return `${a}.${b}`; }평가 후면 아무것도 추가하지
Vitim.us

1

업데이트 됨 : 다음 답변은 단일 변수 이름으로 제한되므로 다음과 같은 템플릿 'Result ${a+b}'은이 경우에 유효하지 않습니다. 그러나 언제든지 템플릿 값을 사용할 수 있습니다.

format("This is a test: ${a_b}", {a_b: a+b});

원래 답변 :

이전 답변을 기반으로하지만보다 "친숙한"유틸리티 기능을 생성합니다.

var format = (template, params) => {
    let tpl = template.replace(/\${(?!this\.)/g, "${this.");
    let tpl_func = new Function(`return \`${tpl}\``);

    return tpl_func.call(params);
}

다음과 같이 호출 할 수 있습니다.

format("This is a test: ${hola}, second param: ${hello}", {hola: 'Hola', hello: 'Hi'});

결과 문자열은 다음과 같아야합니다.

'This is a test: Hola, second param: Hi'

이와 같은 템플릿은 어떻습니까? `Result: ${a+b}`
Atiris

1
안녕하세요 @Atiris, 당신 말이 맞습니다. 그게 한계입니다. 제 답변을 업데이트했습니다.
Roberto

1

다소 간단한 것을 찾고 있다면 (단지 고정 변수 필드, 계산 없음, 조건문…) IE 8,9,10,11과 같은 템플릿 문자열 지원이없는 브라우저 에서도 클라이언트 측 에서 작동 합니다. .

여기에 우리가 간다 :

fillTemplate = function (templateString, templateVars) {
    var parsed = templateString;
    Object.keys(templateVars).forEach(
        (key) => {
            const value = templateVars[key]
            parsed = parsed.replace('${'+key+'}',value)
        }
    )
    return parsed
}

이것은 모든 변수에 대한 조회를 수행합니다. 이 모듈에서 구현 한 모든 항목을 한 번에 대체하는 또 다른 방법이 있습니다. safe-es6-template
Aalex Gabi

1

this.매번 입력해야하는 여분의 중복성에 짜증이 났기 때문에 정규식을 추가하여 다음과 같은 변수를 확장 .a했습니다.this.a .

해결책:

const interp = template => _thisObj =>
function() {
    return template.replace(/\${([^}]*)}/g, (_, k) =>
        eval(
            k.replace(/([.a-zA-Z0-9$_]*)([a-zA-Z0-9$_]+)/, (r, ...args) =>
                args[0].charAt(0) == '.' ? 'this' + args[0] + args[1] : r
            )
        )
    );
}.call(_thisObj);

다음과 같이 사용하십시오.

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!

1

이 작업을 간단히 수행 할 수있는 npm 패키지 하나만 게시합니다. 이 답변에서 깊은 영감을 받았습니다 .

const Template = require('dynamic-template-string');

var tpl = new Template('hello ${name}');

tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';

그 도구는 매우 간단합니다. 당신이 그것을 좋아하기를 바랍니다.


module.exports = class Template {
  constructor(str) {
    this._func = new Function(`with(this) { return \`${str}\`; }`);
  }

  fill(data) {
    return this._func.call(data);
  }
}

1

다음과 같이 인라인 화살표 기능을 사용할 수 있습니다.

const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;

용법:

console.log(template('my replaced string'));

1

런타임 템플릿 문자열

var templateString = (template, values) => {
    let output = template;
    Object.keys(values)
        .forEach(key => {
        output = output.replace(new RegExp('\\$' + `{${key}}`, 'g'), values[key]);
    });
    return output;
};

테스트

console.debug(templateString('hello ${word} world', {word: 'wonderful'}));

0

const fillTemplate = (template, values) => {
  template = template.replace(/(?<=\${)\w+(?=})/g, v=>"this."+v);
  return Function.apply(this, ["", "return `"+template+"`;"]).call(values);
};

console.log(fillTemplate("The man ${man} is brother of ${brother}", {man: "John", brother:"Peter"}));
//The man John is brother of Peter

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.