JavaScript Function
Function 構(gòu)造函數(shù)創(chuàng)建一個新的 Function 對象。直接調(diào)用此構(gòu)造函數(shù)可用動態(tài)創(chuàng)建函數(shù),但會遭遇來自 eval 的安全問題和相對較小的性能問題?!?MDN
Function
可以用來創(chuàng)建函數(shù),JavaScript 中的所有函數(shù),都是 Function對象
。
1. 使用 Function 創(chuàng)建函數(shù)
Function 在被當(dāng)作構(gòu)造函數(shù)調(diào)用的時候,可以用來創(chuàng)建函數(shù)。
var fn = new Function(函數(shù)參數(shù)1, 函數(shù)參數(shù)2, ..., 函數(shù)參數(shù)n, 函數(shù)體);
函數(shù)體是一個字符串,字符串的內(nèi)容是就是函數(shù)調(diào)用時候被執(zhí)行的語句。
var fn = new Function('a', 'b', 'return a + b');
var result = fn(1, 3);
console.log(result); // 輸出:4
將上面創(chuàng)建函數(shù)的方式“翻譯”成常用的創(chuàng)建方式可以是:
var fn = function(a, b) {
return a + b;
};
var result = fn(1, 3);
console.log(result); // 輸出:4
對比一下就很好理解使用 new Function
時候所傳遞的參數(shù)的含義了。
2. 與常規(guī)方式創(chuàng)建函數(shù)的區(qū)別
這里指的常規(guī)方式是指函數(shù)聲明
、函數(shù)表達式
或 ES6 中的箭頭函數(shù)
。
使用 Function 創(chuàng)建的函數(shù),最后一個參數(shù),即函數(shù)體內(nèi)在執(zhí)行的時候作用域是在全局的。
var num = 20;
function fn() {
var num = 10;
var func = new Function('console.log(num)');
console.log(num);
func();
}
fn();
// 輸出:
// 10
// 20
這個例子在執(zhí)行后,依次輸出了 10
,20
,根據(jù)結(jié)果可以知道 new Function
創(chuàng)建的函數(shù),在執(zhí)行過程中,上層作用域是頂級的全局作用域,在瀏覽器下即為 window
。
3. 使用場景
使用 Function 來創(chuàng)建函數(shù)是比較麻煩的,照道理講不會有小伙伴會喜歡用這種方式創(chuàng)建函數(shù)。
Function 的使用主要場景與 eval
類似,用于動態(tài)的運行代碼。
如在線的代碼解析器就可以配合 Function 完成。
var run = function(code, callback) {
window._callback = callback;
var fn = Function(code + ';_callback()');
fn();
};
run('console.log("動態(tài)執(zhí)行的代碼");', function() {
console.log('代碼執(zhí)行后做的事');
});
這樣就可以實現(xiàn)簡單的動態(tài)運行代碼。
注意:真正需要完成這個功能需要大量的細節(jié)處理,如處理輸出,處理異步,絕非這么簡單。
還有一些代碼編譯工具會將編譯后的代碼,使用 new Function
進行包裹,如以下代碼:
var number = 1;
var flag = false;
console.log(number, flag);
上面這份代碼在經(jīng)過編譯后可能會變成:
(new Function('console.log(1,!1)'))()
這樣做是為了縮短代碼,另外就是讓格式化工具無法很好的格式化代碼。
4. 小結(jié)
開發(fā)者通常不會通過內(nèi)建對象 Function
來創(chuàng)建函數(shù),更多的是利用 Function
的特性來動態(tài)執(zhí)行代碼。
通常情況下 Function
創(chuàng)建的函數(shù),在執(zhí)行過程中其 this 是指向最頂層的。