面試官:函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
在 JavaScript 中,我們可以通過 函數(shù)聲明(Function Declaration) 和 函數(shù)表達(dá)式(Function Expression) 來定義函數(shù)。它們在提升(Hoisting)、可讀性、作用域等方面有所不同。
1. 語法區(qū)別
函數(shù)聲明(Function Declaration)
function sayHello() {
console.log("Hello, world!");
}
特點(diǎn):
- 使用 function 關(guān)鍵字直接定義函數(shù)。
- 必須有函數(shù)名(sayHello)。
- 可被提升(Hoisting),可以在聲明前調(diào)用。
函數(shù)表達(dá)式(Function Expression)
const sayHello = function() {
console.log("Hello, world!");
};
特點(diǎn):
- 將函數(shù)賦值給變量(const sayHello = ...)。
- 匿名函數(shù)(Anonymous Function)或具名函數(shù)(Named Function Expression):
a.匿名函數(shù):function() {}(大多數(shù)情況下使用)
b.具名函數(shù):function myFunc() {}(僅在調(diào)試時有用)
- 不會被提升(Hoisting),只能在定義后調(diào)用。
2. 提升(Hoisting)
函數(shù)聲明會被提升
函數(shù)聲明在 JavaScript 解析階段 就會被提升,因此可以在聲明前調(diào)用:
sayHello(); // ? 可以調(diào)用
function sayHello() {
console.log("Hello, world!");
}
解析階段:
// 解析時,相當(dāng)于:
function sayHello() {
console.log("Hello, world!");
}
sayHello(); // 正常執(zhí)行
函數(shù)表達(dá)式不會被提升
函數(shù)表達(dá)式不會被提升,只有在執(zhí)行到賦值代碼后才可以調(diào)用:
sayHello(); // ? 報錯:Cannot access 'sayHello' before initialization
const sayHello = function() {
console.log("Hello, world!");
};
解析階段:
const sayHello; // 變量存在,但未賦值
sayHello(); // ? 報錯
sayHello = function() { console.log("Hello, world!"); };
結(jié)論:
- 函數(shù)聲明:可在定義前調(diào)用
- 函數(shù)表達(dá)式:必須先定義再調(diào)用
3. 作用域 & 調(diào)試
具名函數(shù)表達(dá)式的優(yōu)勢
如果使用 具名函數(shù)表達(dá)式(Named Function Expression, NFE):
const sayHello = function greet() {
console.log("Hello, world!");
};
sayHello(); // ? 正常調(diào)用
greet(); // ? 報錯:greet is not defined
- sayHello() 可用
- greet() 僅在函數(shù)內(nèi)部可用(局部作用域),但在外部不可訪問。
- 好處:
a.提升調(diào)試能力:錯誤棧中會顯示 greet,而不是 anonymous function。
4. 是否可用作 IIFE(立即執(zhí)行函數(shù)表達(dá)式)
函數(shù)表達(dá)式支持 IIFE
(function() {
console.log("立即執(zhí)行!");
})(); // ? 立即執(zhí)行
- IIFE(Immediately Invoked Function Expression,立即執(zhí)行函數(shù)) 需要函數(shù)表達(dá)式。
- 函數(shù)聲明無法用于 IIFE,否則會報錯:
function() {
console.log("錯誤示例");
}(); // ? 語法錯誤
結(jié)論:
- IIFE 只能用函數(shù)表達(dá)式,不支持函數(shù)聲明.
5. 面試高頻問題
面試官:函數(shù)聲明和函數(shù)表達(dá)式的本質(zhì)區(qū)別?
回答:
- 函數(shù)聲明會被提升,可以在定義前調(diào)用;函數(shù)表達(dá)式不會被提升,只能在賦值后調(diào)用。
- 函數(shù)聲明更適合普通函數(shù),函數(shù)表達(dá)式更適合動態(tài)函數(shù)、回調(diào)和 IIFE。
面試官:函數(shù)表達(dá)式能被提升嗎?回答:
- 變量名會被提升,但不會賦值。所以不能在定義前調(diào)用:
console.log(myFunc); // ? undefined
const myFunc = function() {}; // 這里才賦值
面試官:什么時候用函數(shù)表達(dá)式?回答:
- 當(dāng)函數(shù)是回調(diào)時(如 setTimeout、事件監(jiān)聽器)。
- 當(dāng)函數(shù)需要立即執(zhí)行(IIFE)。
- 當(dāng)需要匿名或具名函數(shù)表達(dá)式(例如遞歸或調(diào)試)。
總結(jié)
對比項 | 函數(shù)聲明 | 函數(shù)表達(dá)式 |
定義方式 |
|
|
提升(Hoisting) | ? 提升,可在聲明前調(diào)用 | ? 不提升,必須先定義再調(diào)用 |
是否必須命名 | ? 必須有函數(shù)名 | ? 匿名或具名 |
適合場景 | 適用于普通函數(shù) | 適用于回調(diào)、IIFE |
是否支持 IIFE | ? 不支持 | ? 支持 |
面試高分回答:
“函數(shù)聲明會被提升,可以在定義前調(diào)用,而函數(shù)表達(dá)式不會提升,必須先賦值再調(diào)用。函數(shù)表達(dá)式適用于回調(diào)、IIFE,而函數(shù)聲明適用于普通函數(shù)?!?/span>