shfshanyue / Daily-Question

互联网大厂内推及大厂面经整理,并且每天一道面试题推送。每天五分钟,半年大厂中
https://q.shanyue.tech
4.92k stars 508 forks source link

【Q660】实现一个 render/template 函数,可以用以渲染模板 #678

Open shfshanyue opened 3 years ago

shfshanyue commented 3 years ago
const template = '{{ user["name"] }},今天你又学习了吗 - 用户ID: {{ user.id }}';

const data = {
  user: {
    id: 10086,
    name: '山月',
  }
};

//=> "山月,今天你又学习了吗 - 用户ID: 10086"
render(template, data); 

注意:

  1. 注意深层嵌套数据
  2. 注意 user['name'] 属性

关于复杂的模板编译解析执行,可参考 mustachehandlebars.js

shfshanyue commented 3 years ago

代码可见 实现一个 render/template 函数,可以用以渲染模板 - codepen

function get (source, path, defaultValue = undefined) {
  // a[3].b -> a.3.b -> [a, 3, b]
  const paths = path.replace(/\[(\w+)\]/g, '.$1').replace(/\["(\w+)"\]/g, '.$1').replace(/\['(\w+)'\]/g, '.$1').split('.')
  let result = source
  for (const p of paths) {
    result = result?.[p]
  }
  return result === undefined ? defaultValue : result 
}

function render (template, data)  {
  return template.replace(/{{\s+([^\s]+)\s+}}/g, (capture, key) => {
    return get(data, key)
  })
}
heretic-G commented 3 years ago
function render (template, data) {
    return template.replace(/({{).*?(}})/g, function (...args) {
        return Function(`return this.${args[0].slice(2, -2).trim()}`).call(data)
    })
}
haotie1990 commented 3 years ago
function template(input, data) {
  const regex = RegExp(/\{\{([\w|\.|\[|\]|"]+)\}\}/, 'g');
  let result;
  while((result = regex.exec(input)) !== null) { // input字符串不能修改
    const [pattern, key] = result;
    // 由于改变了原字符串,但regex.lastIndex并未被重置,仍然从此位置开始匹配
    input = input.replace(pattern, eval(`data.${key}`));
    regex.lastIndex = 0; // 重置lastIndex;
  }
  return input;
}
sunwenlong1995 commented 2 years ago

const render = function(template,data){ return template.replace(/{{(.*?)}}/g,($0,$1) => eval('data.' + $1)) }