Quiz |
?
下面Javascript代碼為什么能運(yùn)行?
hello(); function hello(){ alert( "Hello, world!" ); }
但對(duì)于C,這么寫會(huì)報(bào)錯(cuò):
#include " stdio.h " void main(){ hello(); } void hello(){ printf( " Hello, world\n " ); }
由于hello沒(méi)有被預(yù)先聲明,代碼“hello()”被認(rèn)為是隱式聲明,而隱式聲明返回類型是int,所以提示hello類型錯(cuò)誤。
通過(guò)預(yù)先聲明或者將main函數(shù)放在hello函數(shù)的后面可以很容易解決這個(gè)問(wèn)題。
那么對(duì)于Javascript卻能運(yùn)行,這代表了什么呢?
?
被提升的聲明
Javascript引擎會(huì)先對(duì)代碼解釋,將聲明提升,然后再執(zhí)行。例如為了判斷一個(gè)變量定義與否,如果我們?nèi)绱藢懯菚?huì)出引用錯(cuò)誤的:
if (someVar === undefined){ alert( "someVar未定義" ); }
但如果這樣卻不會(huì)出錯(cuò):
if (someVar === undefined){ var someVar = 1; alert( "someVar未定義" ); }
可見(jiàn)聲明被提升了,但只有聲明被提升了,因?yàn)閟omeVar依然等于undefined,而不是1。
值得一提的是,這樣子寫也會(huì)報(bào)錯(cuò):
if (someVar === undefined){ someVar = 1 ; alert( "someVar未定義" ); }
這證明在解釋階段,隱式聲明是沒(méi)有作用的!而且為了讓代碼邏輯清晰,還是用顯式聲明吧!
?
chrome瀏覽器的詭異現(xiàn)象
?chrome瀏覽器(至少在本文簽寫時(shí)的最新版本 22.0.1229.94 m依然是如此 )有個(gè)詭異的現(xiàn)象:
var name = 20 ; alert( typeof (name)); // string name += 12 ; alert(name); // 2012
所以請(qǐng)不要把name定義為除字符串的其他類型,當(dāng)然可以的話也盡量避免使用這個(gè)全局變量吧。
?
函數(shù)的兩種創(chuàng)建方式
函數(shù)申明:
function ?函數(shù)名? ( 參數(shù) 可選 ){ ?函數(shù)體 ? }
函數(shù)表達(dá)式:
function 函數(shù)名 可選 ?(參數(shù) 可選 ){?函數(shù)體 ? }
Syntax
FunctionDeclaration :
function Identifier ( FormalParameterList opt ) { FunctionBody }
FunctionExpression :
function Identifier opt ?( FormalParameterListopt ) { FunctionBody }—— Standard ECMA-262 ECMAScript Language Specification? ?. ECMA
為什么函數(shù)要分聲明( Function Declaration)和表達(dá)式( Function Expression)呢?
譯注:實(shí)際上FunctionDeclaration和FunctionExpression都是函數(shù)產(chǎn)生的語(yǔ)法,這和一般編程語(yǔ)言中函數(shù)聲明只是定義接受參數(shù)數(shù)量及類型與返回值類型不太相同。或者說(shuō),這根本不是字面意義上的函數(shù)聲明。我們可以理解對(duì)于Javascript的函數(shù)聲明(FunctionDeclaration)其實(shí)是聲明式(即需要提升的)函數(shù)產(chǎn)生語(yǔ)法,而函數(shù)表達(dá)式(FunctionExpression)則是表達(dá)式式(即執(zhí)行時(shí)產(chǎn)生)函數(shù)產(chǎn)生語(yǔ)法。
—— WhiteSnow
主要為了區(qū)分函數(shù)的創(chuàng)建是否需要被提升,如果是函數(shù)聲明就需要被提升創(chuàng)建,但如果是表達(dá)式,那么可以在執(zhí)行時(shí)再創(chuàng)建。這樣是很必要的,比如我們可以利用表達(dá)式動(dòng)態(tài)定義函數(shù):
var foo; if (Condition){ foo = function (){ // do something } } else { foo = function (){ // do anything else } }
再比如對(duì)于匿名函數(shù):
( function (){ // do something })();
聲明提升也沒(méi)什么意義,因?yàn)樗粫?huì)在別的地方被引用。
?
如何判斷函數(shù)聲明與函數(shù)表達(dá)式
- 匿名函數(shù)必然是函數(shù)表達(dá)式
- 如果有名字的函數(shù)作為賦值表達(dá)式的一部分那么他也是一個(gè)表達(dá)式
- 如果有名字的函數(shù)被括號(hào)“()”括住,那么他也是一個(gè)表達(dá)式
本文不準(zhǔn)備深入命名函數(shù)表達(dá)式(named function expressions),具體可參見(jiàn)參考文獻(xiàn),不過(guò)一般應(yīng)當(dāng)避免命名函數(shù)表達(dá)式的使用,因?yàn)榇蟛糠止δ芏伎梢杂媚涿瘮?shù)找到替代方案,或者說(shuō)實(shí)際使用中不必考慮命名函數(shù)表達(dá)式。
?
匿名函數(shù)立刻執(zhí)行
我們經(jīng)常希望匿名函數(shù)定義好后立刻執(zhí)行,但這么寫會(huì)拋出語(yǔ)法錯(cuò)誤:
function (){ alert( 1 ); }();
正確寫法如下。
- 聲明一個(gè)函數(shù)對(duì)象,然后執(zhí)行它:
( function (){ alert( 1 ); })();
- 用括號(hào)強(qiáng)制執(zhí)行:
( function (){ alert( 1 ); }());
- 使用void操作符:
void function (){ alert( 1 ); }();
?
總結(jié)
- Javascript中聲明會(huì)被提升;
- 對(duì)于變量顯式聲明提升的僅僅是聲明,賦值并未被提升;
- 對(duì)于函數(shù)聲明由于其賦值和聲明是一體的,所以提升的是整個(gè)函數(shù)的定義;
- 變量隱式聲明和函數(shù)表達(dá)式不會(huì)被提升。
?
思考題
1. 如果我們用函數(shù)表達(dá)式來(lái)創(chuàng)建函數(shù),而不是用函數(shù)聲明來(lái)創(chuàng)建,剛開(kāi)始的題目會(huì)如何呢?
hello(); var hello = function (){ alert( "Hello, world!" ); }
?2. 下面是一個(gè)Button類,并創(chuàng)建了一個(gè)他的實(shí)例,我們可以在瀏覽器中看到一個(gè)按鈕,但是為什么單機(jī)按鈕時(shí)alert出來(lái)的數(shù)值不是13,而是空的呢?如何能alert出我們?cè)O(shè)置的數(shù)值?
function Button(clickFunction) { this .button = document.createElement("button" ); this .button.appendChild(document.createTextNode("Test" )); document.body.appendChild( this .button); this .button.onclick = function (){alert( this .value);} } var bt = new Button(13); // 單擊這個(gè)button的時(shí)候alert出空
?
?
參考資料 |
?
Standard ECMA-262 ECMAScript Language Specification? ?. ECMA .? June 2011
Named function expressions demystified . Juriy "kangax" Zaytsev ?.? June 17, 2009
函數(shù)式JavaScript編程指南 . ShiningRay (譯)?. 2008/01/02
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
