函數
可以實現一定功能的一段代碼的封裝。
注:函數創建過后,在內存堆中以一段字符串文本儲存,不執行時不會產生任何作用,就單單是存了一段字符串。
創建函數
function F65(){ console.log(`我是一個函數F65`); }
let F66 = function () { console.log(`我是一個函數F66`); }
let F66 = function F67() { console.log(`我是一個函數F66`); } F66();//我是一個函數F66 console.log(F66.name);//F67 console.log(F66);//[Function: F67] //F67();//報錯 F67 is not defined
//這個情況有點奇葩
let F68= new Function( "console.log(123)" );
注:內存棧 F68:函數的引用;
內存堆 函數:"console.log(123)",就是個字符串。
函數三要素
一、函數名
函數名取名一般要求是動詞或動賓格式,望文知意,其他的和變量標識符一樣,並且也會和變量名沖突。
二、參數
function F65(a,b,c,...d){ console.log(a,b,c);//A B C console.log(d);//[ 'D', 'E', 'F', 'G', 'H' ] console.log(F65.length);//3 console.log(F65.arguments);//鍵值對的實參 console.log(F65.arguments[0]);//A } F65("A","B","C","D","E","F","G","H");
function f65(x,y,z,i){ console.log(arguments[0]);//1 x=2; console.log(arguments[0]);//2 arguments[0]=5; console.log(x);//5 //形參發生值的改變,相對應的arguments也會發生改變 //arguments發生值的改變,相對應的形參不會發生改變 console.log(i);//un i=2; console.log(i);//2 console.log(arguments[3]);//un //當形參比實參多時,對多的形參進行賦值; //相對應的arguments不改變(即無效,也就是打印undefined) } f65(1,2,3);
注: 函數名.arguments 和直接 arguments 是不一樣的,其實一般都是直接用 arguments。
參數解構
function fn(a,b,{c,d}){ //相當於 let a=參數1; let b=參數2; let {c,d}=參數3; } //意味着參數3傳的是一個對象 //默認值 {c,d=12}={} {}是參數默認值,d=12是解構默認值
三、返回值:return
參數的默認值
函數的形參在書寫時可以直接賦值,(不賦值也會有:undefined),函數被調用時,如果形參有對應的實參,就用實參的值,沒有就用默認值。
給形參傳值:undefined,函數也會使用該形參的默認值(不一定是undefined),
.length獲取形參個數時,有賦值默認值的形參不會計入個數,如果賦值默認值的形參寫在第一個,長度會為0。
因此,推薦把需要賦值默認值的形參寫到最后。
ES6 箭頭函數
x=> num2.has(x) 大多數時候就這個模板,函數返回表達式(num2.has(x))的結果
一般有以下特點:
1、可以省略 書寫 function
2、如果只有一個形參,可以不打小括號
3、如果只有一條執行語句,可以不打大括號
4、只有一條執行語句,並且需要返回這條語句的結果,可以不用寫return
5、不可以使用arguments
6、不會把自己的this綁定到函數上
7、不可以用作構造函數
多數時候使用箭頭函數只有一條語句,就是為了簡潔方便:
let num1 = new Set([1, 2, 3, 4]); let num2 = new Set([3, 4, 5, 6]); // 並集 let union = new Set([...num1,...num2]); console.log(union);//Set { 1, 2, 3, 4, 5, 6 } //交集 let intersect = new Set( [...num1].filter(x=> num2.has(x))); console.log(intersect); //Set { 3, 4 } //差集 let difference = new Set( [...num1].filter(x => !num2.has(x))); console.log(difference); //Set { 1, 2 }
回調函數
把一個函數A,當參數傳遞給另一個函數B進行調用,函數A就是回調函數。
把箭頭函數當做回調函數用的最多。
常用的回調函數
//數組的排序 let arr = [1, 3, 7, 6, 9, 4, 6, 2]; let arr1 = arr.sort( function (a,b){ // return b-a; return a-b; } ) console.log(arr1); console.log(arr.sort((a, b) => a - b)); //升序 console.log(arr.sort((a, b) => b - a)); //降序
回調函數用的非常多,相當重要。
arr.every( function(index){ return index%2==0; } )//以下為簡寫 // every 數組中每個值都滿足條件才返回true console.log(arr.every(index => index % 2 == 0)); //false //some 數組中有一個條件滿足則返回true console.log(arr.some(index => index % 2 == 0)); //true //filter(過濾) 返回所有滿足條件的值 console.log(arr.filter(index => index % 2 == 0)); //[6,6,4,2] //map 返回每個值是否滿足條件 console.log(arr.map(index => index % 2 == 0)); //[ false, false, true, true, true, false, true, false ]
IIFE
Immediately Invoked Function Expression
立即執行函數,創建即調用,調用后即銷毀
注:當立即執行函數中的變量在外面有調用時,變量會不銷毀,但是會“隱形”,只有調用它的“人”看得到。
//一般書寫方式 (function fn(){ console.log("F65"); })() //也可以 (function fn(){ console.log("F65"); }()) !(function fn(){ console.log("F65"); }()) -(function fn(){ console.log("F65"); }()) //主要是為了讓這一段代碼與其他代碼隔開,不會有歧義,形成一個整體
總結
函數的表現形式:
1、聲明式
function fn(){}
2、表達式
let fn = function(){}
3、匿名函數
不需要起名字的地方,function(){},並不能單獨書寫,在特定的地方出現,比如作為一個返回值、參數,或者立即執行函數
function fn(){ return function(){}; }; function fn(function(){}){}; (function(){})();
立即執行函數、回調函數、箭頭函數,都可以算作匿名函數的一種情況。
4、特殊函數、遞歸函數
其實就是函數直接或者間接的調用自己。遞歸一定要給出遞歸結束條件(遞歸出口)。
