大家好,我是IT修真院萌新分院的王寒,一枚正直,純潔,善良的前端程序員。
今天給大家分享一下函數(shù)表達式和函數(shù)聲明有什么區(qū)別?
1.背景介紹
函數(shù)就是一段可以反復(fù)調(diào)用的代碼塊。函數(shù)聲明由三部分組成:函數(shù)名,函數(shù)參數(shù),函數(shù)體。 整體的構(gòu)造是function命令后面是函數(shù)名,函數(shù)名后面是一對圓括號,里面是傳入函數(shù)的參數(shù)。 函數(shù)體放在大括號里面。當(dāng)函數(shù)體沒有使用return關(guān)鍵字返回函數(shù)時,函數(shù)調(diào)用時返回默認的undefined; 如果有使用return語句,則返回指定內(nèi)容。函數(shù)最后不用加上冒號。
function keith() {}
? ? ? ? ? ? ? ? ? ? ? ? ? ?? console.log(keith())?? // 'undefined'
? ? ? ? ? ? ? ? ? ? ? ? ? ?? function rascal(){
? ? ? ? ? ? ? ? ? ? ? ? ? ?? return 'rascal';
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? console.log(rascal())? ? // 'rascal'
2.知識剖析
什么是FUNCTION DECLARATION(函數(shù)聲明)? Function Declaration 可以定義命名的函數(shù)變量,而無需給變量賦值。Function Declaration 是一種獨立的結(jié)構(gòu),不能嵌套在非功能模塊中。 就是使用function關(guān)鍵字聲明一個函數(shù),再指定一個函數(shù)名,叫函數(shù)聲明
函數(shù)聲明是在預(yù)執(zhí)行期執(zhí)行的,也就是說函數(shù)聲明是在瀏覽器準備解析并執(zhí)行腳本代碼的時候執(zhí)行的。所以,當(dāng)去調(diào)用一個函數(shù)聲明時,可以在其前面調(diào)用并且不會報錯。
console.log(rascal())?? // 'rascal'
? ? ? ? ? ? ? ? ? ? ? ? ? ? function rascal(){
? ? ? ?? return 'rascal';
? ?? }
什么是FUNCTION EXPRESSION(函數(shù)表達式)? Function Expression 將函數(shù)定義為表達式語句(通常是變量賦值)的一部分。通過 Function Expression 定義的函數(shù)可以是命名的,也可以是匿名的。Function Expression 不能以“function”開頭。 使用function關(guān)鍵字聲明一個函數(shù),但未給函數(shù)命名,最后將匿名函數(shù)賦予一個變量,叫函數(shù)表達式
簡單點來說函數(shù)表達式是把一個匿名函數(shù)賦給一個全局變量。這個匿名函數(shù)又稱為函數(shù)表達式,因為賦值語句的等號右側(cè)只能放表達式。函數(shù)表達式末尾需要加上分號,表示語句結(jié)束。
var keith = function() {
? ? ? ? //函數(shù)體
? ? };
函數(shù)表達式存儲在變量后,變量也可作為一個函數(shù)使用:
var x = function (a, b) {return a * b};
? ? ? ? ? ? ? ? ? ? ? ? ? ? alert= x(4, 3);
以上函數(shù)實際上是一個 匿名函數(shù) (函數(shù)沒有名稱)。 函數(shù)存儲在變量中,不需要函數(shù)名稱,通常通過變量名來調(diào)用。
var x = function (a, b) {return a * b};
? ? ? ? ? ? ? ? ? ? ? ? var z = x(4, 3);
? ? ? ? ? ? ? ? ? ? ? ? alert= z;
3.常見問題
一、什么是JavaScript函數(shù)?
二、兩者具體有哪些區(qū)別呢?
4.解決方案
1.JavaScript函數(shù)
函數(shù)是由事件驅(qū)動的或者當(dāng)它被調(diào)用時執(zhí)行的可重復(fù)使用的代碼塊
函數(shù)語法:函數(shù)就是包裹在花括號中的代碼塊,使用了關(guān)鍵詞function:
function functionname(){
執(zhí)行代碼
}
當(dāng)調(diào)用該函數(shù)時,會執(zhí)行函數(shù)內(nèi)的代碼。
可以在某事件發(fā)生時直接調(diào)用函數(shù)
調(diào)用帶參數(shù)的函數(shù),在調(diào)用函數(shù)時,可以向其傳遞值,這些值被稱為參數(shù)。這些參數(shù)可以在函數(shù)中使用。 可以發(fā)送任意多的參數(shù),由逗號(,)分隔:
myFunction(argument1,argument2)
當(dāng)聲明函數(shù)時,把參數(shù)作為變量來聲明:
function myFunction(var1,var2){
代碼
}
點擊這個按鈕,來調(diào)用帶參數(shù)的函數(shù)
functionmyFunction(name,job){
alert("Welcome "+ name +", the "+ job);
}
2.函數(shù)聲明和函數(shù)表達式的區(qū)別
1.函數(shù)聲明中函數(shù)名是必須的;函數(shù)表達式中則是可選的
//函數(shù)聲明
function sum(a, b) {
return a + b;
}
alert(sum(1, 2));
//函數(shù)表達式
var s = function sum(a, b) {
return a + b;
}
alert(s(1, 2));
var s = function(a, b) {
return a + b;
}
alert(s(1, 2));//以上兩種都可以
2.用函數(shù)聲明定義的函數(shù),函數(shù)可以在函數(shù)聲明之前調(diào)用,而用函數(shù)表達式定義的函數(shù)只能在聲明之后調(diào)用。
//函數(shù)聲明
alert(sum(1, 2));//3
function sum(a, b) {
return a + b;
}
//函數(shù)表達式:發(fā)生錯誤
try {
alert(s(1, 2));
var s = function sum(a, b) {
return a + b;
}
}
catch (e) {
alert("wrong!");
}
3.以函數(shù)聲明的方法定義的函數(shù)并不是真正的聲明,它們僅僅可以出現(xiàn)在全局中,或者嵌套在其他的函數(shù)中, 但是它們不能出現(xiàn)在循環(huán),條件或者try/catch/finally中,而 函數(shù)表達式可以在任何地方聲明.
//函數(shù)聲明式
function greeting(){
?? console.log("hello world");
}
//函數(shù)表達式
var greeting = function(){
? console.log("hello world");
}
5.擴展思考
使用function關(guān)鍵字聲明一個函數(shù),再指定一個函數(shù)名,叫函數(shù)聲明。
function fn(){……}
使用function關(guān)鍵字聲明一個函數(shù),但未給函數(shù)命名,最后將匿名函數(shù)賦予一個變量,叫函數(shù)表達式。
var fn=function(){……}
使用function關(guān)鍵字聲明一個函數(shù),但未給函數(shù)命名,這個又稱之為什么呢?是屬于以上兩種類型的哪一種?
function(){……}
6.參考文獻
函數(shù)聲明與函數(shù)表達式以及立即執(zhí)行函數(shù)的討論
7.更多討論
問題一:關(guān)于立即執(zhí)行函數(shù)的討論
回答:也就是說只有函數(shù)表達式才能實現(xiàn)立即執(zhí)行,匿名函數(shù)也是函數(shù)表達式為何不能立即執(zhí)行呢?
因為匿名函數(shù)開始的function會被JavaScript引擎識別為函數(shù)聲明的開始,所以加上括號也不會被執(zhí)行
而加上(),!,+,-等符號為什么就可以了呢?
因為加上這些符號就可以告訴js引擎這不是函數(shù)聲明了。
問題二:給匿名函數(shù)用小括號包起來,為什么能執(zhí)行?
//匿名函數(shù):
function(){? //如果不加小括號則會報錯!
alert('彈出框');
}();
//添加小括號后的匿名函數(shù)
(function(){
alert('彈出框');
})();
回答:小括號能把我們的表達式組合分塊,并且每一塊,也就是每一對小括號, 都有一個返回值。這個返回值實際上也就是小括號中表達式的返回值。 加上括號也不會被執(zhí)行
問題三:什么是自執(zhí)行函數(shù)?
回答:在JavaScript里,任何function在執(zhí)行的時候都會創(chuàng)建一個執(zhí)行上下文, 因為function聲明的變量和function有可能只在該function內(nèi)部,這個上下文, 在調(diào)用function的時候,提供了一種簡單的方式來創(chuàng)建自由變量或私有子function。
函數(shù)表達式的作用域
如果函數(shù)表達式聲明的函數(shù)有函數(shù)名,那么這個函數(shù)名就相當(dāng)于這個函數(shù)的一個局部變量,只能在函數(shù)內(nèi)部調(diào)用
var f = function fact(x) {
? ? ? ? if (x <= 1)
? ? ? ? ? ? ? ? return 1;
? ? ? ? else
? ? ? ? ? ? ? ? return x*fact(x-1);
? ? ? ? ? ? };
? ? ? ? ? ? ? alert(fact());? // Uncaught ReferenceError: fact is not defined
fact()在函數(shù)內(nèi)部可以調(diào)用,在函數(shù)外部調(diào)用就會報錯:fact未定義
問題:
1.變量提升:
答案:請點擊
2.?函數(shù)聲明可以先調(diào)用再聲明,是因為變量提升嗎?
這個問題在上面的第一個問題里有提到:
函數(shù)及變量的聲明都將被提升到函數(shù)的最頂部,所以函數(shù)聲明會被先調(diào)用再聲明是以為變量提升
3.函數(shù)聲明在條件語句中使用時注意的問題?
在不同的環(huán)境下用函數(shù)聲明會得到不同的效果
這也是函數(shù)聲明的另外一個重要的特點,即通過條件語句控制函數(shù)聲明的行為并未標準化,因此不同環(huán)境下可能會得到不同的結(jié)果。