eval與new Function的區別

1、簡介

eval和new Function均可以將一段字符串解析成一段JS腳本並執行javascript

2、eval和 new Function的使用

① 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'}

3、eval和new Function的區別

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

4、使用場景

在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節點。

相關文章
相關標籤/搜索