JS模板編譯的實現詳情

前言

編譯是一種格式變成另一種格式的過程。編譯會導致好的結果,比如書寫簡單的代碼,編譯出來復雜的代碼;或者提高代碼的使用性能

這裡隻聊聊模板編譯。

模板編譯的簡單實現

寫一個最簡單的模板

<p>Hello, {{name}}!</p>

這個模板用數據{name: "world"}渲染後的結果是:

<p>Hello, world!</p>

解決方法:最簡單的方案,正則替換就行瞭

const compile = function(template, data) {
  return template.replace(/{{(.+?)}}/g, (match, key) => data[key])
}

const template = "<p>Hello, I'm {{name}}! {{age}} years old!</p>"
const data = {
  name: "hayes",
  age: 18
}
const result = compile(template, data)
console.log(result); // <p>Hello, I'm hayes! 18 years old!</p>

缺點很明顯,除瞭正則替換字段,其他啥都幹不瞭,

來看看簡單的嵌套需求:

模板:

<p>Hello, I'm {{user.name}}! {{user.age}} years old!</p>

渲染數據;

const data = {
  user: {
    name: "hayes",
    age: 18
  }
}

現在再使用上面的方法,就失效瞭。還用正則的話,會很難做。因為需要做語法/詞法分析,來看看大括號內寫的是什麼瞭。

模板編譯

其實對於上述的模板,也可以使用如下方式來寫:

const compile = function(data) {
  return `<p>Hello, I'm ${data.name}! ${data.age} years old!</p>`
}

好處:隻需一次編譯,之後再使用就隻需要直接填充數據即可。而且也方便支持data.user.name這種形式。

工具:使用new Function生成函數

生成一個函數,傳入x和 y,執行return x + y來獲得求和的功能

const fn = new Function("x", "y", "return x + y");

打印fn可以看到輸出的內容如下:

ƒ anonymous(x,y) {
return x + y
}

1、構建模板生成函數

傳入模板字符串,通過new Function方式返回一個新函數。新函數接收一個obj對象

const compile = function(template) {
  // 模板字符串
  let result = "";
  // ...
  return new Function("obj", result);
}

2、正則替換

{{xxx}}找出來,替換為obj.xxx

const compile2 = function(template) {
  // 模板字符串
  let result = template.replace(/{{(.+?)}}/g, (match, key) => {
    return `obj.${key}`
  });
  result = `return "${result}"`;
  return new Function("obj", result);
}
const template2 = "<p>Hello, I'm {{user.name}}! {{user.age}} years old!</p>"
const render2 = compile2(template2)
console.log(render2);

此時,函數打印如下:

ƒ anonymous(obj
) {
return "<p>Hello, I'm obj.user.name! obj.user.age years old!</p>"
}

我們需要把字符串中的obj.user.nameobj.user.age變成動態的。

修改一下正則

const compile2 = function(template) {
  // 模板字符串
  let result = template.replace(/{{(.+?)}}/g, (match, key) => {
    return `" + obj.${key} + "`  // 前後添上加號
  });
  result = `return "${result}"`;
  return new Function("obj", result);
}
const template2 = "<p>Hello, I'm {{user.name}}! {{user.age}} years old!</p>"
const render2 = compile2(template2)
console.log(render2);

再來看看函數的打印:

ƒ anonymous(obj
) {
return "<p>Hello, I'm " + obj.user.name + "! " + obj.user.age + " years old!</p>"
}

最終代碼:

const compile = function(template) {
  // 模板字符串
  let result = template.replace(/{{(.+?)}}/g, (match, key) => {
    return `" + obj.${key} + "`
  });
  result = `return "${result}"`;
  return new Function("obj", result);
}
const template = "<p>Hello, I'm {{user.name}}! {{user.age}} years old!</p>"
const render = compile(template)

const data = {
  user: {
    name: "hayes",
    age: 18
  }
}
const result = render(data)
console.log(result); // <p>Hello, I'm hayes! 18 years old!</p>

渲染結果:

"<p>Hello, I'm hayes! 18 years old!</p>"

到此這篇關於JS模板編譯的實現詳情的文章就介紹到這瞭,更多相關JS模板編譯 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: