函數(shù)的定義方式
- 函數(shù)聲明
- 函數(shù)表達(dá)式
- new Function 構(gòu)造函數(shù)
其中,最常用的是函數(shù)聲明和函數(shù)表達(dá)式逾苫,但這兩者有什么區(qū)別呢卿城?
區(qū)別1:函數(shù)聲明必須始終帶有一個(gè)標(biāo)識(shí)符(Identifier),也就是我們所說(shuō)的函數(shù)名铅搓,而函數(shù)表達(dá)式則可以省略藻雪。
下面看看具體的例子。
function fn() {}; // 函數(shù)聲明
var fn = function() {}; // 函數(shù)表達(dá)式
// 函數(shù)表達(dá)式的另一種寫法
var fn = function foo() {};
函數(shù)聲明的典型格式
function 函數(shù)名稱 (參數(shù):可選){
函數(shù)體
}
function functionName(arg1, arg2, ...){
<!-- function body -->
}
函數(shù)表達(dá)式的典型格式
var valiable = function 函數(shù)名稱(可選)(參數(shù):可選){
函數(shù)體
}
var variable = function(arg1, arg2, ...){
<!-- function body -->
}
var variable = function functionName(arg1, arg2, ...){
<!-- function body -->
}
通過(guò)上面的比較狸吞,我們可以看出:如果不聲明名稱勉耀,那么肯定是函數(shù)表達(dá)式。
也就是說(shuō):如果沒(méi)有函數(shù)名稱蹋偏,那么肯定不是函數(shù)聲明方式便斥。
如果聲明了函數(shù)名稱的話,如何判斷是函數(shù)聲明還是函數(shù)表達(dá)式呢威始?
ECMAScript是通過(guò)它所在的上下文來(lái)判斷的枢纠,如果function fn() {}是作為賦值表達(dá)式的一部分的話,那它就是一個(gè)函數(shù)表達(dá)式黎棠,否則就是函數(shù)聲明晋渺。
區(qū)別2:變量或函數(shù)聲明提前
先看看下面的代碼,運(yùn)行結(jié)果是什么脓斩?
foo();
function foo() {
console.log("執(zhí)行了 foo ...");
}
bar();
var bar = function() {
console.log("執(zhí)行了 bar ...");
}
此時(shí)木西,我們可以看到:foo()正常輸出結(jié)果,而bar()報(bào)錯(cuò)随静。
那如果代碼改為下面這種:
function foo() {
console.log("執(zhí)行了 foo ...");
}
foo();
var bar = function() {
console.log("執(zhí)行了 bar ...");
}
bar();
此時(shí)八千,我們可以看到:foo()和bar()都正常輸出結(jié)果吗讶。
這是什么原因呢?
Javascript的代碼是從上往下執(zhí)行的恋捆,在執(zhí)行的過(guò)程中照皆,會(huì)先進(jìn)行代碼的預(yù)解析,再執(zhí)行代碼沸停。Javascript的預(yù)解析指的是變量或函數(shù)的提升∧せ伲現(xiàn)在回頭看看我們上面寫的代碼。
// foo();
// function foo() {
// console.log("執(zhí)行了 foo ...");
// }
// bar();
// var bar = function() {
// console.log("執(zhí)行了 bar ...");
// }
// 上面的代碼執(zhí)行的時(shí)候愤钾,由于變量或函數(shù)的提升爽茴,相當(dāng)于下面的代碼:
function foo() {
console.log("執(zhí)行了 foo ...");
}
foo();
var bar;
bar();
bar = function() {
console.log("執(zhí)行了 bar ...");
}
從上面的代碼我們可以得出結(jié)論:`函數(shù)聲明會(huì)被提升到當(dāng)前作用域的頂部,函數(shù)表達(dá)式則不會(huì)绰垂。
區(qū)別3:函數(shù)聲明不是一個(gè)完整的語(yǔ)句室奏,所以不能出現(xiàn)在if-else等語(yǔ)句中。
看看下面的代碼劲装,你們知道輸出的是什么結(jié)果嗎胧沫?
if(true) {
function foo() {
console.log('foo - true');
}
} else {
function foo() {
console.log('foo - false');
}
}
foo();
在Chrome瀏覽器中,輸出的結(jié)果為:foo - true占业,但在IE10以下的瀏覽器中绒怨,輸出的結(jié)果為:foo - false。
也就是說(shuō):在現(xiàn)代瀏覽器中谦疾,不會(huì)提升if語(yǔ)句中的函數(shù)聲明南蹂,在老的IE瀏覽器版本中,if語(yǔ)句聲明的函數(shù)也會(huì)提升
念恍。
那么六剥,如果要兼容各個(gè)瀏覽器,上面的代碼該怎樣進(jìn)行修改呢峰伙?
var foo;
if(true) {
foo = function() {
console.log('foo - true');
}
} else {
foo = function() {
console.log('foo - false');
}
}
foo();
此時(shí)疗疟,不管在哪個(gè)瀏覽器中,輸出的結(jié)果都是:foo - true瞳氓。
也就是說(shuō):`函數(shù)聲明不是一個(gè)完整的語(yǔ)句策彤,所以不能出現(xiàn)在if-else,for循環(huán)匣摘,finally店诗,try catch語(yǔ)句中。因?yàn)镋CMAScript規(guī)范只允許他們作為頂級(jí)語(yǔ)句音榜,但是有的瀏覽器并不遵循這個(gè)規(guī)則庞瘸。
總結(jié):函數(shù)聲明可以被提升,但是函數(shù)表達(dá)式不能被提升囊咏。所以恕洲,我們?cè)谌魏挝恢枚x函數(shù)聲明,都可以被使用梅割。但如果是函數(shù)表達(dá)式霜第,只能在函數(shù)表達(dá)式聲明之后調(diào)用它。如果在之前調(diào)用户辞,會(huì)報(bào)Uncaught TypeError的錯(cuò)泌类。