深入理解Js里new Function語法

一般我們不會(huì)使用用 new Function 構(gòu)造函數(shù)的恩闻,因?yàn)闆]必要剧董,直接使用 function 或者 箭頭函數(shù)寫法更簡單。但并不是說new Function 構(gòu)造函數(shù)無用尉剩。在一些特別的場景毅臊,比如函數(shù)體的數(shù)據(jù)格式是字符串的時(shí)候,new Function 構(gòu)造函數(shù)的作用就顯示出來了皂林。之前也是僅僅知道此方法础倍,但是沒有具體的研究搞懂,但是最近一兩年一直在倒騰低代碼的項(xiàng)目著隆,原理上來說呀癣,低代碼都是一堆字符串,為了解析字符串就使用了new Function 構(gòu)造函數(shù)(eval方法也是可以的)浦辨,在此在記錄一下沼沈,加深理解。詳情參見:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions

1芽腾、語法

備注: 不推薦使用 Function 構(gòu)造函數(shù)創(chuàng)建函數(shù)页衙,因?yàn)樗枰暮瘮?shù)體作為字符串可能會(huì)阻止一些 JS 引擎優(yōu)化阴绢,也會(huì)引起其他問題呻袭。把 Function 的構(gòu)造函數(shù)當(dāng)作函數(shù)一樣調(diào)用 (不使用 new 操作符) 的效果與作為 Function 的構(gòu)造函數(shù)調(diào)用一樣腺兴。

let func = new Function ([arg1, arg2, ...argN], functionBody);

//等價(jià)于 let func = Function ([arg1, arg2, ...argN], functionBody);

<font color="red">Function構(gòu)造函數(shù)所有的參數(shù)都是字符串類型。除了最后一個(gè)參數(shù), 其余的參數(shù)都作為生成函數(shù)的參數(shù)即形參篓足。這里可以沒有參數(shù)拘泞。最后一個(gè)參數(shù), 表示的是要?jiǎng)?chuàng)建函數(shù)的函數(shù)體。</font>

//傳入?yún)?shù)
let sum = new Function('a', 'b', 'return a + b');
console.log( sum(1, 2) ); // 3

//不傳入?yún)?shù)
let sum = new Function('console.log(1)');
console.log( sum() ); // 1

由于歷史原因辱魁,new Function參數(shù)也可以以逗號(hào)分隔的列表形式給出诗鸭。下邊這三個(gè)聲明的含義相同:

new Function('a', 'b', 'return a + b'); 
new Function('a,b', 'return a + b'); 
new Function('a , b', 'return a + b');

2、作用域

Function()構(gòu)造函數(shù)和函數(shù)有一點(diǎn)就是:使用構(gòu)造函數(shù)Function()創(chuàng)建的函數(shù)不使用當(dāng)前的詞法作用域锻弓,相反的蝌箍,它們總是被頂級(jí)函數(shù)來編譯,因此在運(yùn)行時(shí)它們只能訪問全局變量和自己的局部變量.

let a = 1
let fn = function(){
  let a = 2
  let result1 = new Function('console.log(a)')
  let result2 = function(){
    console.log(a)
  }
  result1() //打印出1杂拨,訪問的是全局變量a
  result2() //打印出2
}
fn()
// new Function這樣的函數(shù)不能訪問外部變量悯衬,只能訪問全局變量
// 雖然這段代碼可以在瀏覽器中正常運(yùn)行,但在 Node.js 中策橘,result1() 執(zhí)行會(huì)報(bào)錯(cuò)娜亿,因?yàn)檎也坏阶兞?a。
// 這是因?yàn)槁蚓觯?Node 中辰斋,頂級(jí)作用域不是全局作用域,而 a 其實(shí)是在模塊的作用域之中够挂。

想象一下,我們必須從一個(gè)字符串創(chuàng)建一個(gè)函數(shù)枯冈。該函數(shù)的代碼在編寫腳本時(shí)是未知的办悟,但是會(huì)在執(zhí)行過程中知道。我們可能會(huì)從服務(wù)器或其他地方接收到它炫加。此時(shí)我們的新函數(shù)需要與主腳本交互铺然,如果它此時(shí)它可以訪問外部變量,那么就可以操作外部變量魄健,改變外部變量,這樣就會(huì)引發(fā)不可預(yù)估的風(fēng)險(xiǎn)革骨。

3析恋、使用

假如有一個(gè)非合法 JSON 對(duì)象字符串,如下:

  let str = "{ name: '小坦克', code: 100 }" 
  JSON.parse(str) // 會(huì)報(bào)錯(cuò),因?yàn)閟tr字段是不符合規(guī)范的對(duì)象字符串(key,value都必須是""臂外,雙引號(hào)包裹)

可以使用new Function

  let str = "{ name: '小坦克', code: 100 }" 
  let result =  JSON.parse(new Function('return ' + str)()) // result = { name: '小坦克', code: 100 }

4喇颁、new Function和eval的區(qū)別

eval中的代碼執(zhí)行時(shí)的作用域?yàn)楫?dāng)前作用域。它可以訪問到函數(shù)中的局部變量蔫浆。

let a = 1
let fn = function(){
  let a = 2
  let result1 = new Function('console.log(a)')
  let result2 = eval('console.log(a)') //打印出2
  result1() //打印出1姐叁,訪問的是全局變量a
}
fn()

永遠(yuǎn)不要使用 eval !!!

eval() 是一個(gè)危險(xiǎn)的函數(shù)洗显, 它使用與調(diào)用者相同的權(quán)限執(zhí)行代碼挠唆。如果你用 eval() 運(yùn)行的字符串代碼被惡意方(不懷好意的人)修改嘱吗,您最終可能會(huì)在您的網(wǎng)頁/擴(kuò)展程序的權(quán)限下,在用戶計(jì)算機(jī)上運(yùn)行惡意代碼谒麦。更重要的是,第三方代碼可以看到某一個(gè) eval() 被調(diào)用時(shí)的作用域患膛,這也有可能導(dǎo)致一些不同方式的攻擊耻蛇。相似的 Function 就不容易被攻擊

eval() 通常比其他替代方法更慢,因?yàn)樗仨氄{(diào)用 JS 解釋器延曙,而許多其他結(jié)構(gòu)則可被現(xiàn)代 JS 引擎進(jìn)行優(yōu)化。

此外枝缔,現(xiàn)代 JavaScript 解釋器將 JavaScript 轉(zhuǎn)換為機(jī)器代碼蚊惯。這意味著任何變量命名的概念都會(huì)被刪除。因此趴荸,任意一個(gè) eval 的使用都會(huì)強(qiáng)制瀏覽器進(jìn)行冗長的變量名稱查找宦焦,以確定變量在機(jī)器代碼中的位置并設(shè)置其值。另外酝豪,新內(nèi)容將會(huì)通過 eval() 引進(jìn)給變量,比如更改該變量的類型孵淘,因此會(huì)強(qiáng)制瀏覽器重新執(zhí)行所有已經(jīng)生成的機(jī)器代碼以進(jìn)行補(bǔ)償歹篓。但是(謝天謝地)存在一個(gè)非常好的 eval 替代方法:只需使用 window.Function揉阎。這有個(gè)例子方便你了解如何將eval()的使用轉(zhuǎn)變?yōu)镕unction()毙籽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毡庆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌厅翔,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熊泵,死亡現(xiàn)場離奇詭異甸昏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卒蘸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門缸沃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來修械,“玉大人,你說我怎么就攤上這事肯污。” “怎么了哄芜?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵柬唯,是天一觀的道長。 經(jīng)常有香客問我美尸,道長,這世上最難降的妖魔是什么师坎? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蕊温,結(jié)果婚禮上遏乔,老公的妹妹穿的比我還像新娘。我一直安慰自己盟萨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布制轰。 她就那樣靜靜地躺著胞谭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪调俘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天脉漏,我揣著相機(jī)與錄音侧巨,去河邊找鬼。 笑死司忱,一個(gè)胖子當(dāng)著我的面吹牛畴蹭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播繁扎,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼爹梁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姚垃,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤积糯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后看成,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體跨嘉,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了跳纳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寺庄,死狀恐怖力崇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情馍盟,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布贞岭,位于F島的核電站搓侄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏芯侥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一廓俭、第九天 我趴在偏房一處隱蔽的房頂上張望物赶。 院中可真熱鬧,春花似錦酵紫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仰楚。三九已至犬庇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間臭挽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工葬荷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纽帖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓懊直,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瘦陈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容