new 了一個 Function

new Function 和 eval 的區別能夠搜索到蠻多解釋,但總以爲還不夠具體,尋思着補補刀html

1、從簡易模板引擎提及

模板引擎能夠怎樣理解呢? 在一段 Html 文檔裏面有許多佔位符,同時如今還有另外一份 Data 數據,將 Data 注入到 Html 中填充佔位符的方法,就是模板引擎了(簡單得一批)node

既然已經知道目標,那就來簡單實現一個不帶ifelse ifelsefor的(要不我說簡易版嘛),模板定義以下:正則表達式

<html>
  <head>
    <title>{{title}}</title>
  </head>
  <body>
     <p>{{hello + world}}</p>
  </body>
</html>
複製代碼

這裏只有一個關鍵點,就是使用 {{}} 雙花括號做爲模板的佔位符,其中能夠讀取 Data 中的變量,也能夠進行一些簡單合法的 Js 表達式,對應的,準備這樣一份 Data:ui

{
  "title": "facemagic",
  "hello": "hello",
  "world": "world"
}
複製代碼

Now,發揮你的想象,如何才能夠將 Data 注入到 Tpl 當中,輸出目標 Html 字符串?注意到,模板佔位符 {{}} 中的內容至少是一個合法的 Js 表達式,使用正則表達式找到全部佔位符裏的表達式,再經過 eval 來執行,完了把執行結果替換掉佔位符,完美!!!來,走一個:spa

// node 環境

  // data 解構到 global 下
  for (const key in data) {
    global[key] = data[key]
  }
  const regex = /{{([^}]*)}}/g;
  const source = source.replace(regex, (m, n) => {
    let result = m;
    try {
      result = eval(n)
    } catch (e) {
    }
    return result;
  });
複製代碼

Wait a minute !!! 爲毛要將 data 中的元素所有賦值到 global 下? 注意模板表達式的寫法是 {{title}} 而不是 {{data.title}},省略了根索引有木有,爲了執行 eval 不報錯,必須把 data 解構到 global 中。code

這樣就有瑕疵了,若是程序中不當心定義了一個變量恰好跟 data 的某個鍵重名了。那麼可怕的事情將會發生regexp

2、使用 new Function

在上述的狀況中,eval 的方式會形成變量的全局污染,幸運的是,使用 new Function 能夠有效的解決這個問題。奧妙就在於,雖然 new Function 跟 eval 的執行效果相似(前者應該封裝了後者),可是 new Function 是能夠傳參的,是這樣定義的htm

new Function(arg1, arg2, ..., code)
複製代碼

其中,code 能夠直接使用 arg一、arg二、... 例如:模板引擎

const func = new Function(a, b, 'return a+b');
  func(1, 2); // 3
複製代碼

基於此,咱們只須要將 data 解構,做爲參數傳入構造好的 func,就不會有全局污染了:索引

function excute(keys, values, statement) {
  const caller = new Function(...keys, `return (${statement})`);
  return caller(...values);
}

function parse(source, data) {
  const keys = Object.keys(data);
  const values = [];
  for (let i = 0; i < keys.length; i++) {
    values.push(data[keys[i]])
  }
  const regex = /{{([^}]*)}}/g;
  source = source.replace(regex, (m, n) => {
    let result = m;
    try {
      result = excute(keys, values, n);
    } catch (e) {
    }
    return result;
  })
}
複製代碼

嗯嗯,能夠收工了~~

3、總結

舉了一個這麼大大咧咧的栗子,其實想表達的不過是,new Function 相比於 eval 能夠傳入參數,能夠有更好的做用域壁壘。

不過,應該看着不無聊...

相關文章
相關標籤/搜索