【趣味JavaScript】我的天! 居然工作了5年的前端開(kāi)發(fā)都不知道eval函數(shù)其中暗藏玄機(jī)!

「?? 作者:極客小俊
」
「?? 把邏輯思維轉(zhuǎn)變?yōu)榇a的技術(shù)博主
」


eval()函數(shù)介紹
首先你要知道在JS
中eval()函數(shù)
是用來(lái)干嘛的!
它主要的功能就是將一個(gè)JS字符串
解析,然后把它作為腳本代碼
來(lái)執(zhí)行, 要知道字符串
始終就是字符串
是不能被直接執(zhí)行的!
有了eval()函數(shù)
就可以做到, 它的使用語(yǔ)法也很簡(jiǎn)單!
eval(字符串參數(shù));
參數(shù)解釋
傳遞的參數(shù)
其實(shí)是要執(zhí)行的 JavaScript代碼
的字符串形式
!
它的返回值也就是通過(guò)計(jì)算字符串
得到可執(zhí)行
的JS代碼腳本
舉個(gè)栗子
這里有一段代碼
var code='var x=10;var y=20;console.log(x*y)';
如果直接執(zhí)行或打印上面的code變量
那么只能直接輸出這個(gè)字符串
如圖

并且從字符串
中的內(nèi)容上看,很明顯是一段JS代碼
那么我們就可以使用eval()函數(shù)
來(lái)讓它變成一個(gè)可執(zhí)行的JS腳本
代碼如下
var code='var x=10;var y=20;console.log(x*y)';
eval(code);
如圖

eval()函數(shù)特別的使用方法以及原理
按照以上這樣操作,我們只要把可執(zhí)行的JS字符串
丟給eval()函數(shù)
不就行了嗎?
那為什么有些時(shí)候還要加什么小括號(hào)()
?
也就是為什么還要加()變成 eval('('+變量名+')')
呢? ?很多新手會(huì)在這里犯困惑!
那是因?yàn)?code>如果字符串中的語(yǔ)法不正確,eval() 函數(shù)會(huì)拋出語(yǔ)法錯(cuò)誤
w3c文檔
上也有明確的說(shuō)明
如圖

那到底如何來(lái)理解這個(gè)意思呢? 什么叫不是合法的表達(dá)式和語(yǔ)句
呢?
舉個(gè)栗子
var data ='{"張三"}';
console.log("類型為:"+typeof data);
console.log(eval(data));
以上打印結(jié)果如下圖:

但是如果我寫(xiě)成以下這樣就會(huì)給你報(bào)一個(gè)SyntaxError語(yǔ)法錯(cuò)誤
的提示!
如圖

可是你可能會(huì)想,這不就是我們常見(jiàn)的JSON數(shù)據(jù)
嗎,雖然是字符串, 不能直接使用,但是使用eval()函數(shù)
處理以下應(yīng)該可以直接調(diào)用了呀,可為什么會(huì)報(bào)錯(cuò)呢?
原理分析
首先JSON
是一種數(shù)據(jù)格式
,它用于存儲(chǔ)
和交換數(shù)據(jù)
用的,這沒(méi)問(wèn)題吧!
在JSON
中,數(shù)據(jù)被表示為鍵值對(duì)
,這里的鍵
和值
之間用冒號(hào)分隔
,鍵值對(duì)之間用逗號(hào)分隔
,
并且整個(gè)數(shù)據(jù)被包含在大括號(hào){}
當(dāng)中,這也是JSON數(shù)據(jù)
的格式標(biāo)準(zhǔn)
也沒(méi)問(wèn)題對(duì)吧!
可是呢eval()函數(shù)
會(huì)把這個(gè)字符串
的{......}
當(dāng)成一個(gè)Javascript語(yǔ)句塊
來(lái)處理, 那么顯然這樣解析就會(huì)報(bào)錯(cuò)!
我們平常寫(xiě)JS語(yǔ)句塊
都是以下的方式
for(){
? ?..語(yǔ)句塊..
}
if(){
? ?..語(yǔ)句塊..
}
while(){
? ?..語(yǔ)句塊..
}
這些都是語(yǔ)句塊
,也可以叫復(fù)合語(yǔ)句塊
復(fù)合語(yǔ)句塊
是指由多個(gè)語(yǔ)句組成的語(yǔ)句塊
,它們通常被包含在一對(duì)花括號(hào){....}
中
在開(kāi)發(fā)中,復(fù)合語(yǔ)句塊
通常用于控制程序的流程
例如上面說(shuō)到的: if、for、while
等語(yǔ)句的語(yǔ)句體
就是一個(gè)復(fù)合語(yǔ)句塊
。
復(fù)合語(yǔ)句塊
可以包含變量定義、表達(dá)式、控制語(yǔ)句
等多種語(yǔ)句,
這些語(yǔ)句將按照順序依次執(zhí)行,直到復(fù)合語(yǔ)句塊
的結(jié)尾處!
那么你有見(jiàn)過(guò)以下這樣的復(fù)合語(yǔ)句塊
塊嗎?
{
? ?"username":"zhangsan"
}
我們來(lái)運(yùn)行看看效果
如圖

那么很明顯,從JS
基本復(fù)合語(yǔ)句塊
的語(yǔ)法上,這就不能這樣寫(xiě)對(duì)吧! ?從JS語(yǔ)句的語(yǔ)法
上講不通呀!
所以說(shuō)剛剛我們目的是讓eval()函數(shù)
將JSON字符串
解析為一個(gè)對(duì)象
,而不是解析為語(yǔ)句塊
明白了吧!
你也可以理解為是一種強(qiáng)制性
的轉(zhuǎn)換成表達(dá)式
來(lái)進(jìn)行表示!
如果我們不加括號(hào),那么eval()函數(shù)
就可能會(huì)將 這個(gè)JSON字符串
解析為JS語(yǔ)句塊
的形式來(lái)進(jìn)行執(zhí)行,那語(yǔ)句塊
按照這樣取寫(xiě)肯定是錯(cuò)誤的語(yǔ)法呀,從而拋出語(yǔ)法錯(cuò)誤
!
那么就像上面的案例一樣我們也可以讓它正常執(zhí)行成為一個(gè)JSON對(duì)象
代碼如下
({
? ?"username":"zhangsan"
})
給它加上一個(gè)()括號(hào)
嗯嗯 這里非常的精妙!
加了()括號(hào)
以后就表示一個(gè)整體
, 讓JS引擎
知道這是一個(gè)JSON對(duì)象
而非一個(gè)語(yǔ)句塊
, 自然就不會(huì)報(bào)錯(cuò)了!
我們也可以賦值給一個(gè)變量,把這個(gè)JSON對(duì)象
保存起來(lái)進(jìn)行調(diào)用了!
var test=({
? ?"username":"zhangsan"
});
console.log(test.username);
如圖

所以{..}
這種對(duì)象寫(xiě)法
形式,不加外層的小括號(hào)
,會(huì)被識(shí)別為JS代碼塊
的開(kāi)始
和結(jié)束標(biāo)記
注意
那這個(gè)時(shí)候可能就有人要問(wèn)了, 為什么我不加這個(gè)小括號(hào)()
也可以正常執(zhí)行這個(gè)JSON對(duì)象
呢?
代碼如下
var test={"username":"zhangsan"};
console.log(test.username);
如圖

分析解釋
對(duì),根據(jù)JSON
的語(yǔ)法定義上來(lái)說(shuō)這是沒(méi)錯(cuò), 并且你也把這一個(gè)整體
賦值給了一個(gè)變量
進(jìn)行保存!
這跟加一個(gè)小括號(hào)()
一個(gè)道理, 明白了吧! ?JS引擎
沒(méi)有單一的把這{...}
中的內(nèi)容看成是一個(gè)語(yǔ)句塊
而是把這一堆東西,賦值給了一個(gè)變量
成為整體!
eval()函數(shù)使用心得體會(huì)
到這里你再次去理解eval()函數(shù)
在處理字符串的時(shí)候,里面還要加一個(gè)小括號(hào)
是不是就清晰很多了!
eval()
函數(shù)只能接受JS代碼
作為參數(shù),而不能接受JSON格式
的字符串
作為參數(shù)
因此,當(dāng)你將一個(gè)JSON格式
的字符串傳遞給eval()
函數(shù)時(shí),它會(huì)拋出語(yǔ)法錯(cuò)誤
eval()函數(shù)
不是你想傳遞一個(gè)字符串
就一定能給你正確的進(jìn)行解析成可執(zhí)行的代碼!
需要你去觀察你傳遞的字符串
信息是否合理合法, 這也很好的解釋了w3c文檔
中提到的不是合法的表達(dá)式和語(yǔ)句
傳遞給eval()函數(shù)
是會(huì)報(bào)錯(cuò)的!
w3c文檔
上其實(shí)也有明確的規(guī)定, 在處理JSON字符串
的時(shí)候,最好要寫(xiě)成以下方式:
代碼如下
eval('('+jsondata+')');
這樣寫(xiě)的目的是為了讓代碼
更加清晰,更容易理解!
如圖

舉個(gè)栗子
我們假設(shè)一個(gè)JSON字符串
數(shù)據(jù)如下:
var data ='{"username":"張三","age":"20","company":"阿里巴巴"}';
eval(data);
這里直接使用eval()函數(shù)
解析這個(gè)JSON字符串
顯然不能直接解析成JSON對(duì)象
, 因?yàn)閯倓偵厦嫖艺f(shuō)過(guò)了,這里很明顯把這個(gè)JSON字符串
解析成了JS語(yǔ)句塊
,直接報(bào)錯(cuò)!
如圖

那么我們可以給這個(gè)JSON字符串
直接加上一個(gè)小括號(hào)()
看看
代碼如下
var data ='({"username":"張三","age":"20","company":"阿里巴巴"})';
var result=eval(data);
console.log(typeof result);
console.log(result);
如圖

這里就是用了小括號(hào)()
讓JS引擎
把這一堆字符串當(dāng)成一個(gè)整體來(lái)看待!
也就是我們?cè)?code>JSON字符串的兩端添加括號(hào)
,就可以將其轉(zhuǎn)換為一個(gè)整體的JavaScript表達(dá)式
并將結(jié)果存儲(chǔ)在變量中?,F(xiàn)在這個(gè)變量是一個(gè)JS對(duì)象
,我們可以使用它來(lái)訪問(wèn)JSON數(shù)據(jù)
的屬性了!
如果當(dāng)你不加括號(hào)的時(shí)候的時(shí)候{}
會(huì)被解釋成一個(gè)復(fù)合語(yǔ)句塊
所以你經(jīng)??赡軙?huì)見(jiàn)到在使用eval()函數(shù)
解析JSON字符串
的時(shí)候會(huì)寫(xiě)成eval('('+json+')');
這個(gè)樣子
擴(kuò)展
其實(shí)也不用那么麻煩, 直接使用JSON.parse()函數(shù)
就可以解決這個(gè)問(wèn)題了,要解析JSON字符串
直接就用這個(gè),最方便!
var data ='{"username":"張三","age":"20","company":"阿里巴巴"}';
var result=JSON.parse(data);
console.log(typeof result);
console.log(result);
效果跟上面是一樣的!
eval()函數(shù)應(yīng)用場(chǎng)景
我們可能經(jīng)常會(huì)在ajax
提取后端數(shù)據(jù)的時(shí)候,會(huì)獲取到一個(gè)json
數(shù)據(jù),那么可能這個(gè)json
數(shù)據(jù)是一個(gè)字符串,
當(dāng)你拿到之后不能直接使用, 如果直接使用eval()函數(shù)
就會(huì)報(bào)錯(cuò)或者打印不出數(shù)據(jù)返回出undefined
等等結(jié)果!
所以要再eval()函數(shù)
里面加一個(gè)小括號(hào)
如圖




大家的支持就是我堅(jiān)持的動(dòng)力!
如果文章對(duì)你有幫助的話就請(qǐng)
??點(diǎn)贊 ??評(píng)論 ??收藏
一鍵三連哦!
??????????
如果以上內(nèi)容有任何錯(cuò)誤或者不準(zhǔn)確的地方,????歡迎在下面 ?? 留個(gè)言指出!
或者你有更好的想法,歡迎一起交流學(xué)習(xí)????????????