eval和new Function均可以將一段字符串解析成一段JS腳本並執行。javascript
① eval: java
eval做爲一個方法,直接傳入要解析的字符串便可。app
const foo = "foo"; // 定義了一個變量foo const str = "console.log(foo)"; eval(str); // 解析str字符串中包含JS腳本並執行,輸出foo
② new Function:
JS中的每一個函數都是 Function 類型的實例,即JS中全部的函數的proto都指向Function的prototype,或者說,JS中全部的函數都是由Function構造出來的。函數
new Function() 能夠接n個參數,最後一個參數做爲函數體。this
let func = new Function ([arg1[, arg2[, ...argN]],] functionBody);
let foo = new Function("name", "console.log(name)"); // 建立的函數指向Function的原型 console.log(foo.__proto__ === Function.prototype); // true // 等價於 function foo(name) { console.log(name); }
能夠看到Function的最後一個參數字符串"console.log(name)"也被解析成了JS腳本,而且做爲函數體執行了。prototype
須要注意的是,傳入的字符串不是任意的,必須是能當作JS腳本正常執行的字符串。code
const str = "{'foo': '123'}"; const obj = eval(str); console.log(obj); // 報錯信息以下 VM1061:1 Uncaught SyntaxError: Unexpected token ':' at <anonymous>:2:18
由於傳入"{'foo': foo}"的時候,{}會被解析爲代碼塊,至關於直接執行const str = "'foo': foo";解決方法能夠在外層加上一個括號,如:token
const str = "({'foo': '123'})"; const obj = eval(str); console.log(obj);// {foo: '123'}
eval中的代碼執行時的做用域爲當前做用域。它能夠訪問到函數中的局部變量。
new Function中的代碼執行時的做用域爲全局做用域,不論它的在哪一個地方調用的,它訪問的都是全局變量。ip
let foo = "foo"; function bar() { let foo = "bar"; eval("console.log(foo)"); // 輸出bar new Function("console.log(foo)")(); // 輸出foo } bar();
從輸出結果能夠看出,new Function訪問到的始終是全局做用域中的變量;eval訪問到的則是當前做用域中的變量。
固然若是使用的是window.eval()或者global.eval()那麼訪問到的也始終是全局做用域中的變量作用域
let foo = "foo"; function bar() { let foo = "bar"; window.eval("console.log(foo)"); // 輸出foo new Function("console.log(foo)")(); // 輸出foo } bar();
此時輸出都是foo了
若是全局做用域中沒有指定的變量,那麼將會報錯,提示該變量沒有定義。
function bar() { let foo = "bar"; window.eval("console.log(foo)"); // 報錯 new Function("console.log(foo)")(); // 報錯 } bar(); // 報錯信息以下 VM1051:1 Uncaught ReferenceError: foo is not defined at eval (eval at bar ((index):3), <anonymous>:1:13) at eval (<anonymous>) at bar (<anonymous>:3:12) at <anonymous>:6:1
在Vue生成渲染函數的時候會使用到,Vue中進行模板編譯的時候,最終會將模板編譯成一段可執行JS字符串,而後傳遞給new Function生成渲染函數,渲染(掛載)的時候,執行這個渲染函數拿到對應的虛擬DOM節點,如:
// template模板 <div id="app" style="color: red;background: blue;"><p>hello {{name}}</p>{{msg}}</div>
// 解析模板生成一段字符串,即渲染函數要執行的字符串 let code = _c("div", {id: "app",style: {"color":" red","background":" blue"}},_c("p", undefined,_v("hello"+_s(name))),_v(_s(msg)))
// 將渲染函數要執行的字符串傳入new Function()生成渲染函數 let renderFn = new Function(`with(this) {return ${code}}`);
等到渲染的時候,就會執行渲染函數,即renderFn(),此時就會執行code所指的字符串,拿到對應的虛擬DOM節點,進行patch最終更新真實的DOM節點。