문자열을 템플릿 문자열로 변환


147

템플릿 문자열을 일반적인 문자열로 만들 수 있습니까?

let a="b:${b}";

그런 다음 템플릿 문자열로 변환

let b=10;
console.log(a.template());//b:10

않고 eval, new Function동적 코드 생성의 다른 수단?


5
이것을 달성 할 수있는 방법을 찾았습니까? 언젠가는해야 할지도 모르고, 당신이 도착한 것이 무엇인지 궁금합니다.
Bryan Rayner

@BryanRayner는 js 프로그램이 URL이 config.js 파일에 문자열 "/ resources / <resource_id> / update /"로 나머지 API에서 데이터를 가져 오려고한다고 말하고 프로그램에서 동적으로 "resource_id"를 넣습니다. . 해당 URL을 여러 부분으로 나누고 다른 영역에 저장하지 않으려면 일종의 문자열 템플릿 처리가 필요합니다.
Ryu_hayabusa


eval을 사용하는 대신 Eval을 정규식으로 사용하는 것이 좋습니다. 권장하지 않으며 권장하지 않으므로 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…를 사용하지 마십시오! 하자 b = 10; a = "b : $ {b}"; 응답하자 = a.replace (/ \ $ {\ w +} /, b); conssole.log (응답);
Vijay Palaskar

답변:


79

템플릿 문자열은 b런타임에 변수를 동적으로 참조해야 하므로 대답은 NO입니다. 동적 코드 생성 없이는 불가능합니다.

그러나 eval그것은 매우 간단합니다.

let tpl = eval('`'+a+'`');

7
eval은 안전하지 않으므로 동적 코드 생성의 다른 수단도 있습니다
KOLANICH

8
@KOLANICH 특히이 경우 a문자열 에서 따옴표를 이스케이프 하면 훨씬 덜 안전 let tpl = eval('`'+a.replace(/`/g,'\\`')+'`');합니다. eval컴파일러가 코드를 최적화하지 못하게 하는 것이 더 중요하다고 생각 합니다. 그러나 나는이 질문과 관련이 없다고 생각합니다.
alexpods

3
실제로 템플릿 문자열 내에서 함수를 실행할 수도 있습니다.
KOLANICH

9
@KOLANICH 죄송합니다 eval. 그러나 템플릿 리터럴 자체는 형식입니다 eval. 두 가지 예 : var test = Result: ${alert('hello')}; var test = Result: ${b=4}; 둘 다 스크립트 컨텍스트에서 임의의 코드를 실행하게됩니다. 임의의 문자열을 허용하려면 allow뿐만 아니라 허용 할 수도 있습니다 eval.
Manngo

6
조심해. babel과 같은 것이 이것을 번역하지 않기 때문에이 코드는 IE에서 작동하지 않습니다
cgsd

79

내 프로젝트에서 ES6을 사용하여 이와 같은 것을 만들었습니다.

String.prototype.interpolate = function(params) {
  const names = Object.keys(params);
  const vals = Object.values(params);
  return new Function(...names, `return \`${this}\`;`)(...vals);
}

const template = 'Example text: ${text}';
const result = template.interpolate({
  text: 'Foo Boo'
});
console.log(result);

업데이트 lodash 의존성을 제거했습니다. ES6에는 키와 값을 얻는 동등한 방법이 있습니다.


1
안녕하세요, 귀하의 솔루션은 훌륭하게 작동하지만 React Native (빌드 모드)에서 사용하면 오류가 발생합니다. 유효하지 않은 문자 '`' 이지만 디버그 모드에서 실행할 때 작동합니다. 바벨 문제, 어떤 도움?
Mohit Pandey

@ MohitPandey PhantomJS 에서이 코드의 테스트를 실행할 때 동일한 오류가 발생했으며 크롬에서 전달되었습니다. 이 경우 ES6를 더 잘 지원하는 새로운 PhantomJS 베타 버전이 설치되어 있다고 생각합니다.
Mateusz Moska

1
불행히도, 그것은 작동하지 않으며 동일한 정규 표현식을 작성했습니다. 답변으로 추가되었습니다.
Mohit Pandey

이 솔루션은 템플릿 문자열에
백틱

내가 그것을 시도 할 때 나는 얻었다 ReferenceError: _ is not defined. ES6 코드가 아닌 lodash특정 코드 입니까?
xpt

29

당신이 요구하는 것 :

//non working code quoted from the question
let b=10;
console.log(a.template());//b:10

에 (전력, 어, 안전의 측면에서) 정확히 동일하다 eval: 코드를 포함하는 문자열을 가지고 그 코드를 실행하는 능력; 또한 실행 된 코드가 호출자의 환경에서 로컬 변수를 볼 수있는 기능.

JS에서 함수가 아닌 한 호출자의 로컬 변수를 볼 수있는 방법은 없습니다 eval(). 심지어 Function()는 할 수 없습니다.


JavaScript에 "template strings"라는 소리가 들리면 Mustache와 같은 내장 템플릿 라이브러리라고 가정하는 것이 당연합니다. 그렇지 않습니다. 주로 JS의 문자열 보간 및 여러 줄 문자열입니다. 그래도 이것이 한동안 일반적인 오해가 될 것이라고 생각합니다. :(


2
TBH는 내가 생각했던 것입니다. 매우 편리했을 것입니다.
Bryan Rayner

이 (아직) 작동합니까? 을 받고 template is not a function있습니다.
Ionică Bizău

2
이 답변의 맨 위에있는 코드 블록은 질문의 인용문입니다. 작동하지 않습니다.
Jason Orendorff

27

아니요, 동적 코드 생성 없이는이를 수행 할 수있는 방법이 없습니다.

그러나 템플릿 문자열을 내부적으로 사용하여 일반 문자열을 값 맵을 제공 할 수있는 함수로 변환하는 함수를 만들었습니다.

템플릿 문자열 요지 생성

/**
 * Produces a function which uses template strings to do simple interpolation from objects.
 * 
 * Usage:
 *    var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
 * 
 *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
 *    // Logs 'Bryan is now the king of Scotland!'
 */
var generateTemplateString = (function(){
    var cache = {};

    function generateTemplate(template){
        var fn = cache[template];

        if (!fn){
            // Replace ${expressions} (etc) with ${map.expressions}.

            var sanitized = template
                .replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
                    return `\$\{map.${match.trim()}\}`;
                    })
                // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                .replace(/(\$\{(?!map\.)[^}]+\})/g, '');

            fn = Function('map', `return \`${sanitized}\``);
        }

        return fn;
    }

    return generateTemplate;
})();

용법:

var kingMaker = generateTemplateString('${name} is king!');

console.log(kingMaker({name: 'Bryan'}));
// Logs 'Bryan is king!' to the console.

이것이 누군가를 돕기를 바랍니다. 코드에 문제가 있으면 Gist를 업데이트하십시오.


감사! 자바 스크립트 sprintf 솔루션 대신 이것을 사용했습니다.
seangwright

1
모든 템플릿 var test = generateTemplateString('/api/${param1}/${param2}/') console.log(test({param1: 'bar', param2: 'foo'}))반환에 대해 작동하지 않습니다/api/bar//
Guillaume Vincent

고마워요 정규식에 두 번 일치해야했을 때 $ {param1} / $ {param2}의 단일 일치 항목이 포함되었습니다.
Bryan Rayner

이 기능은 IE11에서 작동하지 않습니다. 백 틱에 대한 지원이 없기 때문입니다.
s.meijer

1
물론 브라우저에서 템플릿 문자열을 지원하지 않으면이 방법이 작동하지 않습니다. 지원되지 않는 브라우저에서 템플릿 문자열을 사용하려면 TypeScript와 같은 언어 또는 Babel과 같은 트랜스 파일러를 사용하는 것이 좋습니다. 이것이 ES6를 이전 브라우저로 가져 오는 유일한 방법입니다.
Bryan Rayner

9

TLDR : https://jsfiddle.net/w3jx07vt/

모든 사람들이 변수에 접근하는 것을 걱정하는 것 같습니다. 왜 전달하지 않습니까? 호출자에서 변수 컨텍스트를 가져 와서 전달하는 것이 너무 어렵지 않을 것이라고 확신합니다. 이 https://stackoverflow.com/a/6394168/6563504 를 사용 하여 obj에서 소품을 가져옵니다. 나는 지금 당신을 테스트 할 수 없지만 이것은 효과가 있습니다.

function renderString(str,obj){
    return str.replace(/\$\{(.+?)\}/g,(match,p1)=>{return index(obj,p1)})
}

테스트했습니다. 다음은 전체 코드입니다.

function index(obj,is,value) {
    if (typeof is == 'string')
        is=is.split('.');
    if (is.length==1 && value!==undefined)
        return obj[is[0]] = value;
    else if (is.length==0)
        return obj;
    else
        return index(obj[is[0]],is.slice(1), value);
}

function renderString(str,obj){
    return str.replace(/\$\{.+?\}/g,(match)=>{return index(obj,match)})
}

renderString('abc${a}asdas',{a:23,b:44}) //abc23asdas
renderString('abc${a.c}asdas',{a:{c:22,d:55},b:44}) //abc22asdas

@ s.meijer 당신은 정교한 수 있습니까? 이 코드를 성공적으로 사용하고 있습니다. jsfiddle.net/w3jx07vt
M3D

1
더 나은 정규 표현식을 사용하면 ${}문자를 선택할 수 없습니다 . 시도 :/(?!\${)([^{}]*)(?=})/g
Eric Hodonsky

@Relic jsfiddle.net/w3jx07vt/2 나는 그 일을 할 수 없었고, 손을 빌려 주려고 내 포스트를 업데이트 할까? :)
M3D

그래서 당신이 그것을 잡으려는 방식은 실제로별로 도움이되지 않습니다. 대신 문자열 바꾸기를 대신했습니다. 보간 단계를 추가하는 대신 문자열을 interp 또는 string으로 사용할 수 있습니다. 공상은 아니지만 효과가있었습니다.
Eric Hodonsky

8

여기서 문제는 호출자의 변수에 액세스 할 수있는 함수를 갖는 것입니다. 이것이 eval템플릿 처리에 직접 사용되는 이유 입니다. 가능한 해결책은 사전 속성에 의해 명명 된 형식 매개 변수를 가져와 같은 순서로 해당 값으로 호출하는 함수를 생성하는 것입니다. 다른 방법은 다음과 같이 간단한 것입니다.

var name = "John Smith";
var message = "Hello, my name is ${name}";
console.log(new Function('return `' + message + '`;')());

그리고 Babel 컴파일러를 사용하는 사람이라면 누구나 생성 된 환경을 기억하는 클로저를 만들어야합니다.

console.log(new Function('name', 'return `' + message + '`;')(name));

첫 번째 스 니펫은 eval전역 name변수 에서만 작동하기 때문에 실제로 더 나쁩니다.
Bergi

@Bergi 문장이 유효합니다-함수의 범위가 없어집니다. 문제에 대한 쉬운 해결책을 제시하고 싶었던 일에 대한 간단한 예를 제시하고자했습니다. 하나는 단순히 문제를 극복하기 위해 다음과 같이 올 수있다 : var template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return '+ 메시지 +';')();}
didinko

아니, 정확히 그 것 무엇을 하지 작업 - new Function에 액세스 할 수 없습니다 var nametemplate기능을.
Bergi

두 번째 저격은 내 문제를 해결했습니다 ... 나에게서 투표하십시오! 감사합니다. 이는 iframe으로의 동적 라우팅과 관련된 일시적인 문제를 해결하는 데 도움이되었습니다.
Kris Boyd

7

여기에 게시 된 좋은 솔루션이 많이 있지만 ES6 String.raw 메소드 를 사용하는 솔루션은 아직 없습니다 . 여기에 나의 설득이 있습니다. 전달 된 객체의 속성 만 허용한다는 점에서 중요한 제한 사항이 있습니다. 즉 템플릿에서 코드 실행이 작동하지 않습니다.

function parseStringTemplate(str, obj) {
    let parts = str.split(/\$\{(?!\d)[\wæøåÆØÅ]*\}/);
    let args = str.match(/[^{\}]+(?=})/g) || [];
    let parameters = args.map(argument => obj[argument] || (obj[argument] === undefined ? "" : obj[argument]));
    return String.raw({ raw: parts }, ...parameters);
}
let template = "Hello, ${name}! Are you ${age} years old?";
let values = { name: "John Doe", age: 18 };

parseStringTemplate(template, values);
// output: Hello, John Doe! Are you 18 years old?
  1. 문자열을 인수가 아닌 텍스트 부분으로 나눕니다. 정규식을 참조하십시오 .
    parts: ["Hello, ", "! Are you ", " years old?"]
  2. 문자열을 속성 이름으로 분할하십시오. 일치하지 않으면 배열을 비 웁니다.
    args: ["name", "age"]
  3. obj특성 이름별로 매개 변수를 맵핑하십시오 . 얕은 한 수준 매핑으로 솔루션이 제한됩니다. 정의되지 않은 값은 빈 문자열로 대체되지만 다른 잘못된 값은 허용됩니다.
    parameters: ["John Doe", 18]
  4. 활용 String.raw(...)하고 결과를 반환합니다.

호기심에서 String.raw는 실제로 여기에 어떤 가치를 제공합니까? 문자열을 파싱하고 서브 레이션이 무엇인지 추적하는 모든 작업을 수행하는 것 같습니다. 단순히 .replace()반복해서 호출하는 것과 다른 점이 있습니까?
Steve Bennett 1

페어 포인트, @SteveBennett. 일반 문자열을 템플릿 문자열로 변환하는 데 문제가 있었고 원시 객체를 직접 작성하여 솔루션을 찾았습니다. String.raw를 연결 방법으로 줄 였지만 꽤 잘 작동한다고 생각합니다. 나는 다음과 같은 멋진 솔루션을보고 싶다 .replace():) 나는 가독성이 중요하다고 생각한다. 따라서 정규 표현식을 사용하는 동안 모든 것을 이해하도록 돕기 위해 그것들을 명명하려고 노력한다.
pekaaw

6

다니엘의 대답은 (그리고 s.meijer의 유사 요점 )하지만 더 읽기 :

const regex = /\${[^{]+}/g;

export default function interpolate(template, variables, fallback) {
    return template.replace(regex, (match) => {
        const path = match.slice(2, -1).trim();
        return getObjPath(path, variables, fallback);
    });
}

//get the specified property or nested property of an object
function getObjPath(path, obj, fallback = '') {
    return path.split('.').reduce((res, key) => res[key] || fallback, obj);
}

참고 : 이것은 s.meijer의 원본을 약간 향상시킵니다 ${foo{bar}(정규 표현식은 ${과 중괄호가 아닌 문자 만 허용합니다 }).


업데이트 : 이것을 사용하여 예제를 요청 받았으므로 여기로 이동하십시오.

const replacements = {
    name: 'Bob',
    age: 37
}

interpolate('My name is ${name}, and I am ${age}.', replacements)

실제로 이것을 사용하여 예제를 게시 할 수 있습니까? 이 자바 스크립트는 저를 약간 뛰어 넘습니다. /\$\{(.*?)(?!\$\{)\}/g(중괄호를 처리하기 위해) 정규 표현식을 제안합니다 . 작동하는 솔루션이 있지만 그것이 당신만큼 이식성이 있는지 잘 모르겠습니다. 그래서 이것이 페이지에서 어떻게 구현되어야하는지 알고 싶습니다. 내도 사용합니다 eval().
정규 Joe

내가 나서서뿐만 아니라 답변을 게시, 나는 그보다 안전하고 성능 마음을 만드는 방법에 대한 귀하의 의견 싶어요 : stackoverflow.com/a/48294208를 .
정규 Joe

@RegularJoe 예제를 추가했습니다. 내 목표는 간단하게 유지하는 것이었지만 중첩 된 중괄호를 처리하려면 정규식을 변경해야한다는 것이 맞습니다. 그러나 일반 문자열을 템플릿 리터럴 (이 함수의 전체 목적) 인 것처럼 평가할 때 유스 케이스를 생각할 수 없습니다. 무엇을 염두에 두셨습니까?
Matt Browne

또한 저는 성능 전문가 나 보안 전문가가 아닙니다. 내 대답은 실제로 두 개의 이전 답변을 결합한 것입니다. 그러나 사용 eval하면 보안 문제를 일으킬 수있는 실수에 훨씬 더 개방적이지만 내 버전에서하는 일은 점으로 구분 된 경로에서 객체의 속성을 찾는 것입니다. 안전해야합니다.
Matt Browne

5

예를 들어 문자열 프로토 타입을 사용할 수 있습니다

String.prototype.toTemplate=function(){
    return eval('`'+this+'`');
}
//...
var a="b:${b}";
var b=10;
console.log(a.toTemplate());//b:10

그러나 원래 질문에 대한 답은 길이 없습니다.


5

나는 s.meijer의 답변을 좋아했고 그의 것을 기반으로 내 자신의 버전을 썼습니다.

function parseTemplate(template, map, fallback) {
    return template.replace(/\$\{[^}]+\}/g, (match) => 
        match
            .slice(2, -1)
            .trim()
            .split(".")
            .reduce(
                (searchObject, key) => searchObject[key] || fallback || match,
                map
            )
    );
}

1
산뜻한! 정말 깔끔합니다!
xpt

4

Internet Explorer를 지원하는이 방법이 필요했습니다. IE11에서도 백틱이 지원되지 않는 것으로 나타났습니다. 또한; 사용 eval하거나 이에 상응하는 Function것이 옳지 않다고 생각합니다.

그 통지를 위해; 나는 또한 백틱을 사용하지만, 이들은 바벨과 같은 컴파일러에 의해 제거됩니다. 다른 방법으로 제안 된 방법은 런타임에 따라 다릅니다. 전에 말했듯이; 이것은 IE11 이하의 문제입니다.

그래서 이것은 내가 생각해 낸 것입니다.

function get(path, obj, fb = `$\{${path}}`) {
  return path.split('.').reduce((res, key) => res[key] || fb, obj);
}

function parseTpl(template, map, fallback) {
  return template.replace(/\$\{.+?}/g, (match) => {
    const path = match.substr(2, match.length - 3).trim();
    return get(path, map, fallback);
  });
}

출력 예 :

const data = { person: { name: 'John', age: 18 } };

parseTpl('Hi ${person.name} (${person.age})', data);
// output: Hi John (18)

parseTpl('Hello ${person.name} from ${person.city}', data);
// output: Hello John from ${person.city}

parseTpl('Hello ${person.name} from ${person.city}', data, '-');
// output: Hello John from -

"eval 또는 동등한 기능을 사용하는 것이 옳지 않다고 생각합니다." ... 예. 동의합니다. 그러나 이것이 "음, 사용합시다"라고 말할 수있는 몇 안되는 사용 사례 중 하나라고 생각합니다. jsperf.com/es6-string-tmpl을 확인 하십시오 -실제 사용 사례입니다. 귀하의 함수 (내와 동일한 정규 표현식 사용) 및 광산 (평가 + 문자열 리터럴) 감사! :)
Andrea Puddu 2017

@AndreaPuddu, 실제로 성능이 향상되었습니다. 그러나 다시; IE에서는 템플릿 문자열이 지원되지 않습니다. 따라서 eval('`' + taggedURL + '`')단순히 작동하지 않습니다.
s.meijer

"독립적으로 보인다"는 말이 나아졌다. 격리 된 상태에서 테스트 되었기 때문이다. 그 테스트의 유일한 목적은를 사용하여 잠재적 인 성능 문제를 확인하는 것이었다 eval. 템플릿 리터럴 관련 : 다시 지적 해 주셔서 감사합니다. Babel을 사용하여 코드를 변환하고 있지만 기능이 여전히 작동하지 않습니다.
Andrea Puddu

3

현재 기존 답변에 댓글을 달 수 없으므로 Bryan Raynor의 탁월한 답변에 직접 댓글을 달 수 없습니다. 따라서이 답변은 약간의 수정으로 그의 대답을 업데이트 할 것입니다.

간단히 말해서, 그의 함수는 실제로 작성된 함수를 캐시하지 못하므로 이전에 템플리트를 보았는지 여부에 관계없이 항상 다시 작성합니다. 올바른 코드는 다음과 같습니다.

    /**
     * Produces a function which uses template strings to do simple interpolation from objects.
     * 
     * Usage:
     *    var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
     * 
     *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
     *    // Logs 'Bryan is now the king of Scotland!'
     */
    var generateTemplateString = (function(){
        var cache = {};

        function generateTemplate(template){
            var fn = cache[template];

            if (!fn){
                // Replace ${expressions} (etc) with ${map.expressions}.

                var sanitized = template
                    .replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
                        return `\$\{map.${match.trim()}\}`;
                    })
                    // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                    .replace(/(\$\{(?!map\.)[^}]+\})/g, '');

                fn = cache[template] = Function('map', `return \`${sanitized}\``);
            }

            return fn;
        };

        return generateTemplate;
    })();

3

@Mateusz Moska, 솔루션은 훌륭하게 작동하지만 React Native (빌드 모드)에서 사용하면 오류가 발생합니다 : 잘못된 문자 '`' 이지만 디버그 모드에서 실행할 때 작동합니다.

그래서 정규식을 사용하여 자체 솔루션을 작성했습니다.

String.prototype.interpolate = function(params) {
  let template = this
  for (let key in params) {
    template = template.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), params[key])
  }
  return template
}

const template = 'Example text: ${text}',
  result = template.interpolate({
    text: 'Foo Boo'
  })

console.log(result)

데모 : https://es6console.com/j31pqx1p/

참고 : 나는 문제의 근본 원인을 알 수 없기 때문에, 나는 반응 네이티브 REPO에서 티켓 제기 https://github.com/facebook/react-native/issues/14107을 너무 한번 그들이 할 수있는 수, 같은에 대해 수정 / 안내 :)


백틱 문자가 포함 된 템플릿을 지원합니다. 그러나 템플릿 패턴을 만들려고 시도하는 대신 콧수염이나 이와 유사한 것을 사용하는 것이 좋습니다 . 템플릿이 얼마나 복잡한 지에 따라,이 경우는 고려하지 않는 무차별 대입 방식입니다. 키에는 특수 정규식 패턴이 포함될 수 있습니다.
SliverNinja-MSFT

2

여전히 역동적이지만 나체 평가를 사용하는 것보다 더 통제력이있는 것 같습니다.

const vm = require('vm')
const moment = require('moment')


let template = '### ${context.hours_worked[0].value} \n Hours worked \n #### ${Math.abs(context.hours_worked_avg_diff[0].value)}% ${fns.gt0(context.hours_worked_avg_diff[0].value, "more", "less")} than usual on ${fns.getDOW(new Date())}'
let context = {
  hours_worked:[{value:10}],
  hours_worked_avg_diff:[{value:10}],

}


function getDOW(now) {
  return moment(now).locale('es').format('dddd')
}

function gt0(_in, tVal, fVal) {
  return _in >0 ? tVal: fVal
}



function templateIt(context, template) {
  const script = new vm.Script('`'+template+'`')
  return script.runInNewContext({context, fns:{getDOW, gt0 }})
}

console.log(templateIt(context, template))

https://repl.it/IdVt/3


1

이 솔루션은 ES6없이 작동합니다.

function render(template, opts) {
  return new Function(
    'return new Function (' + Object.keys(opts).reduce((args, arg) => args += '\'' + arg + '\',', '') + '\'return `' + template.replace(/(^|[^\\])'/g, '$1\\\'') + '`;\'' +
    ').apply(null, ' + JSON.stringify(Object.keys(opts).reduce((vals, key) => vals.push(opts[key]) && vals, [])) + ');'
  )();
}

render("hello ${ name }", {name:'mo'}); // "hello mo"

참고 : Function생성자는 항상 전역 범위에서 생성되므로 템플릿으로 전역 변수를 덮어 쓸 수 있습니다.render("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});


0

우리는 자바 스크립트에서 멋진 기능이 될 수있는 바퀴를 재발 명하기 때문에.

eval()안전하지 않은을 사용 하지만 자바 스크립트는 안전하지 않습니다. 나는 자바 스크립트가 훌륭하지 않다는 것을 쉽게 인정하지만 필요가 있었고 대답이 필요했기 때문에 하나를 만들었습니다.

리터럴의 여러 줄 기능을 사용할 때까지 평가 하지 않고 리터럴의 여러 줄 기능을 사용하고 싶기 때문에 변수 @대신 $을 사용하여 변수를 양식화하기로 선택했습니다 . 변수 구문은@{OptionalObject.OptionalObjectN.VARIABLE_NAME}

나는 자바 스크립트 전문가가 아니기 때문에 기꺼이 개선에 대한 조언을하지만 ...

var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
for(i = 0; i < myResultSet.length; i++) {
    prsLiteral = rt.replace(prsRegex,function (match,varname) {
        return eval(varname + "[" + i + "]");
        // you could instead use return eval(varname) if you're not looping.
    })
    console.log(prsLiteral);
}

매우 간단한 구현은 다음과 같습니다

myResultSet = {totalrecords: 2,
Name: ["Bob", "Stephanie"],
Age: [37,22]};

rt = `My name is @{myResultSet.Name}, and I am @{myResultSet.Age}.`

var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
for(i = 0; i < myResultSet.totalrecords; i++) {
    prsLiteral = rt.replace(prsRegex,function (match,varname) {
        return eval(varname + "[" + i + "]");
        // you could instead use return eval(varname) if you're not looping.
    })
    console.log(prsLiteral);
}

실제 구현에서는을 사용하기로 선택했습니다 @{{variable}}. 중괄호 하나 더. 예상치 못한 일이 발생하지 않을 것입니다. 그 정규식은 다음과 같습니다./\@\{\{(.*?)(?!\@\{\{)\}\}/g

쉽게 읽을 수 있도록

\@\{\{    # opening sequence, @{{ literally.
(.*?)     # capturing the variable name
          # ^ captures only until it reaches the closing sequence
(?!       # negative lookahead, making sure the following
          # ^ pattern is not found ahead of the current character
  \@\{\{  # same as opening sequence, if you change that, change this
)
\}\}      # closing sequence.

당신이 정규식 경험하지 않는 경우, 매우 안전 규칙은 모든 영숫자가 아닌 문자를 탈출하는 것입니다,하지 않으며 지금까지 많은 탈출 문자 정규식의 거의 모든 맛에 특별한 의미를 가지고 불필요하게 문자를 탈출.


0

Andrea Giammarchi의 github 에서이 작은 JS 모듈을 사용해보십시오 : https://github.com/WebReflection/backtick-template

/*! (C) 2017 Andrea Giammarchi - MIT Style License */
function template(fn, $str, $object) {'use strict';
  var
    stringify = JSON.stringify,
    hasTransformer = typeof fn === 'function',
    str = hasTransformer ? $str : fn,
    object = hasTransformer ? $object : $str,
    i = 0, length = str.length,
    strings = i < length ? [] : ['""'],
    values = hasTransformer ? [] : strings,
    open, close, counter
  ;
  while (i < length) {
    open = str.indexOf('${', i);
    if (-1 < open) {
      strings.push(stringify(str.slice(i, open)));
      open += 2;
      close = open;
      counter = 1;
      while (close < length) {
        switch (str.charAt(close++)) {
          case '}': counter -= 1; break;
          case '{': counter += 1; break;
        }
        if (counter < 1) {
          values.push('(' + str.slice(open, close - 1) + ')');
          break;
        }
      }
      i = close;
    } else {
      strings.push(stringify(str.slice(i)));
      i = length;
    }
  }
  if (hasTransformer) {
    str = 'function' + (Math.random() * 1e5 | 0);
    if (strings.length === values.length) strings.push('""');
    strings = [
      str,
      'with(this)return ' + str + '([' + strings + ']' + (
        values.length ? (',' + values.join(',')) : ''
      ) + ')'
    ];
  } else {
    strings = ['with(this)return ' + strings.join('+')];
  }
  return Function.apply(null, strings).apply(
    object,
    hasTransformer ? [fn] : []
  );
}

template.asMethod = function (fn, object) {'use strict';
  return typeof fn === 'function' ?
    template(fn, this, object) :
    template(this, fn);
};

데모 (다음 모든 테스트가 true를 리턴 함) :

const info = 'template';
// just string
`some ${info}` === template('some ${info}', {info});

// passing through a transformer
transform `some ${info}` === template(transform, 'some ${info}', {info});

// using it as String method
String.prototype.template = template.asMethod;

`some ${info}` === 'some ${info}'.template({info});

transform `some ${info}` === 'some ${info}'.template(transform, {info});

0

함수로 설명이있는 유형을 수행하는 자체 솔루션을 만들었습니다.

export class Foo {
...
description?: Object;
...
}

let myFoo:Foo = {
...
  description: (a,b) => `Welcome ${a}, glad to see you like the ${b} section`.
...
}

그리고 그렇게 :

let myDescription = myFoo.description('Bar', 'bar');

0

eval을 사용하는 대신 정규식을 사용하는 것이 좋습니다.

Eval은 권장하지 않으며 권장하지 않으므로 사용하지 마십시오 ( mdn eval ).

 let b = 10;
 let a="b:${b}";

let response = a.replace(/\${\w+}/ ,b);
conssole.log(response);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.