定義
常規定義
function 函數名(參數)
{
...
}
匿名函數
無需給函數取名,舉例:
let x = function() { ... }
箭頭函數
舉例:
let x = data => { ... }
通過原型構建
通過Function
對象,可以構建函數,舉例:
x = new Function("x", "y", "return x + y")
x(1, 2)
// 3
函數參數
函數里參數個數和調用時傳入的參數個數沒有限制,比如:
function fun(x,y)
{
alert(x)
alert(y)
return x+y
}
alert(fun(1))
結果依次彈出:
1 undefined NaN
因為只傳入1,所以x=1,但是y沒有值所以就是未賦值的undefined
,而number和一個非number相加,就會顯示NaN
上面那個調用時還可以傳入超過函數定義的參數個數,舉例:
alert(fun(1,2,3,4,5))
結果依次彈出:
1 2 3
arguments
函數參數還可以用arguments
來代替,其相當于一個數組,用來存放傳過來所有實參,函數如果有形參,就分別按順序對應,比如arguments[0]
對應第一個形參…,且arguments
接收參數數量不限,舉例求接收的所有參數值之和:
function abc() {
num = 0;
for (i = 0; i < arguments.length; i++) {
num += arguments[i]
}
return num;
}
alert(abc(1, 2, 3, 4, 5, 6));
注意點
函數聲明function xxx(){}/xxx = function(){}區別
前者會被加入到window
對象里,后者用let
之類的聲明就不會壓到window
對象里,舉例:
console.log(window.history);
function history() {
console.log(1);
}
console.log(window.history);
// 會發現window.history被覆蓋了,不過這里由于涉及到函數提升問題,所以如果一起執行會發現兩次輸出的都是被覆蓋過的函數
而使用let
結果:
console.log(window.history);
let history = function() {
console.log(1);
}
console.log(window.history);
// 會發現history沒有覆蓋window對象下的history
因此前者也被稱為全局函數定義,后者為匿名函數定義
函數提升
test();
function test() {
...
}
會發現執行成功,相當于:
function test() {
...
}
test();
而匿名函數的方式則不一樣:
test();
let test = function() {
...
}
會發現test沒定義,因為let的暫時性死區問題,然后通過var
定義:
test();
var test = function() {
...
}
會發現test定義了,但不是一個函數,因為變量提升,test
現在是undefined,即下面這樣:
var test;
test();
test = function() {
...
}
立即執行函數
通過該方式作為插件之類的時候可以避免作用域沖突問題:
(function() {
function aaa() {}
})()
例如下面這塊代碼,aaa就無法被直接使用,此時我們可以將其放入一個對象里,對外暴露接口:
(function(window) {
function aaa() {}
function bbb() {}
window.$ = {aaa, bbb}
})(window)
$.aaa()
// 此時aaa和bbb必須通過`$`來調用
當然通過let
定義匿名函數的話,上面的內容還可以這樣解決:
{
let aaa = function () {};
let bbb= function () {};
window.$ = {aaa, bbb}
}
caller/callee
參考:
https://blog.csdn.net/qq_17335153/article/details/52575064
https://blog.csdn.net/chaoguo1234/article/details/81277945
https://blog.csdn.net/Web_J/article/details/88995450