JS 函数 声明函数 函数三要素 箭头函数 回调函数
函数
可以实现一定功能的一段代码的封装。
注:函数创建过后,在内存堆中以一段字符串文本储存,不执行时不会产生任何作用,就单单是存了一段字符串。
创建函数
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、特殊函数、递归函数
其实就是函数直接或者间接的调用自己。递归一定要给出递归结束条件(递归出口)。