JS立即執行如何使用?還是說圓括弧本身是用來改變JS的執行上下文環境?
首先,根據JS高級程序設計中第七章提到(P185,第四版),函數聲明後面無法跟圓括弧,只有表達式可以。但是,這段代碼:
前幾個是將函數聲明轉換為表達式 不會報錯,但是function(){return "hello world";}() 本身會報錯,但是小括弧放在外面 ( function(){return "hello world";}() )卻也不會報錯?函數應該執行外層嵌套的括弧 中裡面的內容吧,可是裡面的內容本身就會報錯啊。再舉個栗子:eval()將Json轉換為JS對象需要使用小括弧,這個是因為什麼原因?
//for example
eval("{ foo: 123 }")
123
&> eval("({ foo: 123 })")
{ foo: 123 }
所以個人推測是JS中圓括弧本身會改變JS執行上下文....
補充資料和來源:為什麼JS中eval處理JSON數據要加括弧_javascript技巧eval解析JSON字元串的一個小問題[譯]JavaScript中:表達式和語句的區別
瀉藥
再次強調
沒事兒時候去看看規範先說 eval 這個由於 {} 並不僅僅表示對象直接量
還表示語法塊其中的 key: 也不僅僅為 object·的屬性名定義還有 label 語法聲明也是如此所以{ foo: 123 }
會表示為語法塊中含有 名為 foo 的 label
其後值數字直接量而不是對象直接量表示加入括弧({ foo: 123 })
語法就不同了
括弧內需要按照表達式解析所以裡頭得是 Expression而不能是 Statement
ObjectLiteral 就在基本表達式中此時的{xx:xxx}就會被解析為對象直接量而不是語法塊+label完全與你理解的什麼改變執行上下文沒關係在說 function 其實同理的FunctionDeclaration 與 Statement 同級別所以直接寫
function(){}
會被優先解釋為FunctionDeclaration
而非FunctionExpression雖然他們很像就差個 Identifier (FunctionExpression 的 Identifier 標註是 opt 可選的)此時 function(){} 會被認為是 FunctionDeclaration 但是缺少 Identifier 標示符而被認為是語法錯誤後面跟上() 也不過是function(){}
()
這樣了
第一行函數定義就語法錯誤
所以不能執行而FunctionExpression之所以可以被成功進行語法解析是因為他得放在該放的地方就是 Expression 之中才行前面說了() 里是啥是個 Expression 啊(function(){})()
也好
(function(){}())
也好
裡面的function(){}均為函數表達式而不是函數定義同理
只要在 Expression 里的都行+function(){}()
-function(){}()
!function(){}()
....
等等都可以
只因為 + - !等後面是緊跟 一元表達式 (UnaryExpression)一元表達式又屬於 Expressions甚至if (function(a){return a &> 1}(2)) {
alert("hehehe")}switch (function(a){return a - 5}(8)) {
case function(b){return b - 2}(5) : alert("hehehe")}
只要在 Expressions 里
都是可以被當做函數表達式解析的同跟你理解的什麼改變執行上下文沒關係不過項目里你可千萬別跟上頭這麼寫會被別人打死……你說的這些都是語法解析造成的,跟運行、context 沒一毛錢關係。
我覺得吧, ( function(){return "hello world";}() )最外面的括弧()起到運算符的作用,跟!、+、-、=一樣,把函數聲明轉換成函數表達式了。
我來強行跑個題露個臉。在 @貘吃饃香 老師的回答的基礎上,說明一下我對函數表達式一個細節的理解。
摘自我在SegmentFault上的一個回答。
-------------------------------- 聽說要來個分割線--------------------------------
var f = function g(){ return 23; }; typeof g(); 報錯,而不是「number」
var f = function g(){ return 23; }; typeof g();
為什麼是報錯,而不是「number」,
強行回答一個~ 補充一下@manxisuo 的答案。
(以下截圖均來自ES5標準文檔,內容是本人閱讀後的理解)
首先,我們知道函數的定義有兩種方式:
- 函數聲明 (FunctionDeclaration)
- 函數表達式 (FunctionExpression)
函數聲明在程序 (Program) 中有著非比尋常的優先順序:
一段ES程序就是由語句 (Statement) 和函數聲明組成的。
顯然 ``var f = function g(){ return 23; };`` 是一段語句,而非函數聲明。具體來說,是一段變數語句 (VariableStatement) 。等號右側被解釋為賦值語句(AssignmentExpression) ,再經過一系列的解釋後,被確定為函數表達式。等號左側變數將被賦值為右側函數表達式解釋執行後的引用。
因此問題的關鍵在於函數表達式是如何解釋執行的。
再看函數表達式的語法,函數名是一個可選項。而函數名的有無,函數表達式的解釋執行步驟有著巨大的差異。
function ( FormalParameterListopt ) { FunctionBody }
當沒有函數名時,函數表達式的解釋執行與函數聲明相似,作用域即為當前執行的詞法環境。後者,函數聲明會執行一個抽象方法CreateMutableBinding,在環境記錄項中創建一個新的可變綁定(即變數)。從這裡可以知道,新創建的變數就在當前的作用域內。
function Identifier ( FormalParameterListopt ) { FunctionBody }
重點來了,指定了函數名的函數表達式,會首先執行一個抽象方法NewDeclarativeEnvironment,該方法創建一個空的新詞法環境,並把 當前的執行環境 引用為 新的詞法環境的外部詞法環境。然後以新的詞法環境為作用域,執行了接下來的步驟,並最後將函數的引用交給左側的變數。因此這裡的函數名,是綁定在新的詞法環境中的,外部環境也就無法找到函數名,拋出了ReferenceError。
另外@manxisuo 所說,也同樣可以解釋了。
以上。
Reference
- ECMA-262標準文檔- ES5/函數定義eval一個對象需要加上括弧是因為如果不加上括弧的話,會被當成是一個代碼塊,在代碼塊裡面寫foo: 123就不是對象。函數表達式才能立即執行,函數聲明不能,上面的!、()讓函數聲明變成函數表達式,所以能立即執行。
人家的解釋器就那麼寫的,就那麼定義的,跟上下文沒關係,參考編譯原理的基礎知識,詞法分析,語法分析,語義分析等等,分清代碼與程序的界限
第一個報錯是解析出錯,瀏覽器不知道你寫的是個啥。eval不加圓括弧一樣可以運行,但是沒有任何返回,沒有意義,加括弧返回的就是對象。
推薦閱讀:
※js 中,不使用數組,不使用對象,可以 return 多組值嗎?
※TypeScript 的命運會不會和 CoffeeScript 一樣 ?
※如何看待阿里開源的Rax框架?
※瀏覽器端js有如何為本機生成固定的uuid?
※有沒有必要將 DOM 結構緩存到本地?如果有,意義是什麼?
TAG:前端開發 | JavaScript | JavaScript語言精粹 |