微信搜尋 【大遷世界】, 我會第一時間和你分享前端行業趨勢,學習途徑等等。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。
在 JavaScript 中,function
關鍵字可以完成一個簡單的工作:建立一個函式。 但是,使用關鍵字定義函式的方式可以建立具有不同屬性的函式。
在本文中,我們來看一下,如何使用function
關鍵字來定義函式宣告和函式表示式,以及這兩種函式之間的區別又是什麼。
1.函式表示式vs函式宣告
函式宣告和函式表示式是使用 function
關鍵字建立函式的2種方法。
舉個例子來說明差異,我們建立兩個版本的 sums 函式:
function sumA(a, b) {
return a + b;
}
(function sumB(a, b) {
return a + b;
});
sumA(1, 2); // ???
sumB(1, 2); // ???
動手試試:https://jsfiddle.net/dmitri_p...
一般情況,像往常一樣定義函式(sumA函式
)。在另一種情況下,函式被放置在一對括號中(sumB函式
)。
如果呼叫 sumA(1,2)
和 sumB(1,2)
會發生什麼?
如預期的那樣,sumA(1, 2)
返回 3
。但是,呼叫sumB(1, 2)
會引發異常:Uncaught ReferenceError: sumB is not defined
。
其原因是sumA
是使用函式宣告建立的,該函式宣告在當前作用域中建立一個函式變數(具有與函式名稱相同的名稱)。 但是sumB
是使用函式表示式建立的(將其包裝在括號中),該函式表示式不會在當前作用域內建立函式變數。
如果你想訪問使用函式表示式建立的函式,那麼將函式物件儲存到一個變數中:
// Works!
const sum = (function sumB(a, b) {
return a + b;
});
sum(1, 2); // => 3
如果語句以`function`關鍵字開頭,則為函式宣告,否則為函式表示式。
// 函式宣告:以`function`關鍵字開頭
function sumA(a, b) {
return a + b;
}
// 函式表示式:不以`function`關鍵字開頭
const mySum = (function sumB(a, b) {
return a + b;
});
// 函式表示式:不以`function`關鍵字開頭
[1, 2, 3].reduce(function sum3(acc, number) {
return acc + number
});
從更高的角度來看,函式宣告對於建立獨立函式很有用,但是函式表示式可以用作回撥。
現在,我們更深入地研究函式宣告和函式表示式的行為。
2.函式宣告
在前面的示例中已經看到的,sumA
是一個函式宣告:
// Function declaration
function sumA(a, b) {
return a + b;
}
sumA(4, 5); // => 9
當一個語句包含function
關鍵字,後跟函式名稱,一對帶引數的括號(param1, param2, paramN)
以及包圍在一對花括號{}
中的函式主體時,就會發生函式宣告。
函式宣告會建立一個函式變數:一個與函式名稱同名的變數(例如,上一個示例中的sumA
)。 在當前作用域中(在函式宣告之前和之後),甚至在函式作用域本身內,都可以訪問該函式變數。
函式變數通常用於呼叫函式或將函式物件傳遞給其他函式(傳遞給高階函式)。
例如,編寫一個函式 sumArray(array)
,以遞迴方式累加一個陣列的項(該陣列可以包含數字或其他陣列):
sumArray([10, [1, [5]]]); // => 16
function sumArray(array) {
let sum = 0;
for (const item of array) {
sum += Array.isArray(item) ? sumArray(item) : item;
}
return sum;
}
sumArray([1, [4, 6]]); // => 11
動手試試:https://jsfiddle.net/dmitri_p...
function sumArray(array) { ... }
是函式宣告。
包含函式物件的函式變數sumArray
在當前作用域中可用:sumArray([10, [1, [5]]])
之前和sumArray([1, [4, 6]])
之後,函式宣告, 以及函式本身的作用域sumArray([1, [4, 6]])
(允許遞迴呼叫)。
由於提升,函式變數在函式宣告之前可用。
2.1 函式宣告的注意事項
函式宣告語法的作用是建立獨立函式。 函式宣告應在全域性作用域內,或直接在其他函式的作用域內:
// Good!
function myFunc1(param1, param2) {
return param1 + param2;
}
function bigFunction(param) {
// Good!
function myFunc2(param1, param2) {
return param1 + param2;
}
const result = myFunc2(1, 3);
return result + param;
}
基於相同的原因,不建議在條件(if
)和迴圈(while
,for
)中使用函式宣告:
// Bad!
if (myCondition) {
function myFunction(a, b) {
return a * b;
}
} else {
function myFunction(a, b) {
return a + b;
}
}
myFunction(2, 3);
使用函式表示式更好地執行有條件地建立函式。
3.函式表示式
當function
關鍵字在表示式內部建立函式(帶有或不帶有名稱)時,將出現函式表示式。
以下是使用表示式建立的函式的示例:
// Function expressions
const sum = (function sumB(a, b) {
return a + b;
});
const myObject = {
myMethod: function() {
return 42;
}
};
const numbers = [4, 1, 6];
numbers.forEach(function callback(number) {
console.log(number);
// logs 4
// logs 1
// logs 1
});
在函式表示式中建立了兩種函式:
- 如果表示式中的函式沒有名稱,例如
function(){return 42}
,那是一個匿名函式表示式 - 如果函式具有名稱,例如 上一個示例中的
sumB
和回撥,那麼這是一個命名函式表示式
3.1 函式表示式的注意事項
函式表示式適合作為條件建立的回撥或函式:
// Functions created conditionally
let callback;
if (true) {
callback = function() { return 42 };
} else {
callback = function() { return 3.14 };
}
// Functions used as callbacks
[1, 2, 3].map(function increment(number) {
return number + 1;
}); // => [2, 3, 4]
如果已建立命名函式表示式,請注意,該函式變數僅在建立的函式作用域內可用:
const numbers = [4];
numbers.forEach(function callback(number) {
console.log(callback); // logs function() { ... }
});
console.log(callback); // ReferenceError: callback is not defined
試一試:https://jsfiddle.net/dmitri_p...
callback
是一個命名的函式表示式,因此callback函式變數僅在callback()
函式使用域可用,而在外部則不可用。
但是,如果將函式物件儲存到常規變數中,則可以在函式作用域內外從該變數訪問函式物件:
const callback = function(number) {
console.log(callback); // logs function() { ... }
};
const numbers = [4];
numbers.forEach(callback);
console.log(callback); // logs function() { ... }
試一試:https://jsfiddle.net/dmitri_p...
4. 總結
根據使用function
關鍵字建立函式的方式,可以透過兩種方法來建立函式:函式宣告和函式表示式。
留個問題: function sum(a, b) { return a + b } + 1
是函式宣告還是函式表示式,可以在留言中說出你的答案。
編輯中可能存在的bug沒法實時知道,事後為了解決這些bug,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug。
原文:https://dmitripavlutin.com/ja...
交流
有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。
本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。