好家伙,本篇為《JS高級程式設計》第十章“函數”學習筆記 1.函數的三種定義方式:函數表達式、函數聲明及箭頭函數 函數聲明: function sum(a) { return a + 1; } 函數表達式: let sum= function(a){ return a + 1; } 箭頭函數: le ...
好家伙,本篇為《JS高級程式設計》第十章“函數”學習筆記
1.函數的三種定義方式:函數表達式、函數聲明及箭頭函數
函數聲明:
function sum(a) {
return a + 1;
}
函數表達式:
let sum= function(a){
return a + 1;
}
箭頭函數:
let sum = (a) => {
return a + 1;
}
以函數聲明方式聲明的函數存在"函數聲明提升",
在執行代碼時,JavaScript 引擎會先執行一遍掃描, 把發現的函數聲明提升到源代碼樹的頂部。
因此即使函數定義出現在調用它們的代碼之後,引擎也會把 函數聲明提升到頂部。
而函數表達式這麼做會報錯(箭頭函數同樣報錯)
代碼如果沒有執行到函數表達式的那一行,那麼執行上下文中就沒有函數的定義
2.函數名
函數名是指向函數的指針,所以它們跟其他包含對象指針的變數具有相同的行為。
function sum(num1, num2) { return num1 + num2; } console.log(sum(10, 10)); // 20
let anotherSum = sum;
console.log(anotherSum(10, 10)); // 20
sum = null;
console.log(anotherSum(10, 10)); // 20
以上代碼定義了一個名為 sum()的函數,用於求兩個數之和。
然後又聲明瞭一個變數 anotherSum, 並將它的值設置為等於 sum。
註意,使用不帶括弧的函數名會訪問函數指針,而不會執行函數。
此時, anotherSum 和 sum 都指向同一個函數。
調用 anotherSum()也可以返回結果。把 sum 設置為 null 之後,就切斷了它與函數之間的關聯。
而 anotherSum()還是可以照常調用,沒有問題。(有意思,之前不清楚)
ECMAScript 6 的所有函數對象都會暴露一個只讀的 name 屬性,其中包含關於函數的信息。
多數情 況下,這個屬性中保存的就是一個函數標識符,或者說是一個字元串化的變數名。
即使函數沒有名稱, 也會如實顯示成空字元串。
function AAA(){}
let BBB =function (){}
let CCC =()=>{}
console.log(AAA.name);
console.log(BBB.name);
console.log(CCC.name);
console.log((()=>{}).name);
(最後一行有東西的,空字元)
3.參數
ECMAScript 函數的參數跟大多數其他語言不同。
ECMAScript 函數既不關心傳入的參數個數,也不 關心這些參數的數據類型。
定義函數時要接收兩個參數,並不意味著調用時就傳兩個參數。
你可以傳一 個、三個,甚至一個也不傳,解釋器都不會報錯。(好家伙)
4.沒有重載
js沒有重載
(這可真是太有意思了,方法名是指針,參數不管數量,我想js自然是不會有重載的)
方法後定義覆蓋先定義(記住了,要考的)
function add(num) {
return num + 100;
}
function add(num) {
return num + 200;
}
let result = add(100); // 300
顯然,定義兩個同名參數,後定義的會覆蓋先定義的
5.arguments屬性
arguments 是一個類數組對象,包含調用函數時傳入的所有參數。
function test(a,b,c,d,e){
console.log(arguments)
}
test(1,2,3,4);
5.1.arguments.callee
arguments 對象其實還有一個 callee 屬性,是一個指向 arguments 對象所在函數的 指針。
想不出什麼好的例子,就用書中的原例吧:
(書中原例)
一個階乘遞歸
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
隨後用arguments.callee代替factorial
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
這時候可能有人會問了,這有什麼屌用.我剛開始也是這麼想的,後來又看了兩遍,發現js開發者還是有點東西的
使用 arguments.callee 就可以讓函數邏輯與函數名解耦
我們接著看:
(重要的一個例子)
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
let trueFactorial = factorial;
factorial = function () {
return 0;
};
console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0
這段就有意思了,
trueFactorial 變數被賦值為 factorial,所以console.log(trueFactorial(5));結果為120;
但是console.log(factorial(5)); 結果又為0;
trueFactorial 不受factorial方法重寫的影響
這一個例子就幫我們記住了三個知識點:
1.函數名真的是指針
2.使用 arguments.callee 就可以讓函數邏輯與函數名解耦
3.js有重寫,莫得重載
6.caller屬性
caller屬性引用的是調用當前函數的函數,或者如果是 在全局作用域中調用的則為 null。
function outer() {
inner();
}
function inner() {
console.log(arguments.callee.caller);
}
outer();