Convert a string to a template string

前端 未结 19 2150
轮回少年
轮回少年 2020-11-22 08:30

Is it possible to create a template string as a usual string

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

an then convert it into a template string

le         


        
相关标签:
19条回答
  • 2020-11-22 09:21

    As your template string must get reference to the b variable dynamicly (in runtime), so the answer is: NO, it impossible to do without dynamic code generation.

    But with eval it's pretty simple:

    let tpl = eval('`'+a+'`');
    
    0 讨论(0)
  • 2020-11-22 09:22

    Still dynamic but seems more controlled than just using a naked eval:

    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('ffffdd')
    }
    
    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

    0 讨论(0)
  • 2020-11-22 09:24

    Instead of using eval better is use to regex

    Eval it's not recommended & highly discouraged, so please don't use it (mdn eval).

     let b = 10;
     let a="b:${b}";
    
    let response = a.replace(/\${\w+}/ ,b);
    conssole.log(response);
    
    0 讨论(0)
  • 2020-11-22 09:27

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

    Everyone seems to be worried about accessing variables, why not just pass them? I'm sure it wont be too hard to get the variable context in the caller and pass it down. Use this https://stackoverflow.com/a/6394168/6563504 to get the props from obj. I can't test for you right now, but this should work.

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

    Tested. Here is full code.

    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
    
    0 讨论(0)
  • 2020-11-22 09:30

    I currently can't comment on existing answers so I am unable to directly comment on Bryan Raynor's excellent response. Thus, this response is going to update his answer with a slight correction.

    In short, his function fails to actually cache the created function, so it will always recreate, regardless of whether it's seen the template before. Here is the corrected code:

        /**
         * 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;
        })();
    
    0 讨论(0)
  • 2020-11-22 09:31

    In my project I've created something like this with 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);

    UPDATE I've removed lodash dependency, ES6 has equivalent methods to get keys and values.

    0 讨论(0)
提交回复
热议问题