一、函数定义
1.方式一 function 函数名(参数){ 函数体 }——————函数声明的方法
function fn(a){ console.log(a); };
2.方式二 var 变量名 = function(参数){ 函数体 }——————函数表达式
var fn=function(a){ console.log(a); };
3.注意的问题:
- 函数必须先定义,再调用
//先声明 function fn(a){ console.log(a); } //调用函数 fn(1);
- 函数最好一个功能一个函数
- 函数推荐使用驼峰式命名
function getMax(a,b){ if(a<b){ console.log(b); }else{ console.log(a); } }; getMax(2,3);//3
- 有名字的函数称为命名函数;反之,没有名字的函数称为匿名函数
- 方式二定义的函数称为函数表达式,把一个函数给一个变量,调用函数用 变量名(参数)
- 函数表达式声明的函数后面要加分号
- 区别:函数声明的方法重名会覆盖,函数表达式相当于变量的再赋值
function f1(){ console.log("我是第一个函数"); }; function f1(){ console.log("我是第二个函数,我覆盖了第一个函数") }; f1();//我是第二个函数,我覆盖了第一个函数
var f2=function(){ console.log("我是第一个函数") }; f2=function(){ console.log("我是第二个函数") }; f2();//我是第二个函数
- 函数的自调用,没有名字,调用------声明的同时,一次性的
fn=function(){ console.log("函数fn代表整个函数代码,后面加括号就是调用"); }();//会输出内容,相当于fn()的调用,简写版
二、参数
1.形参:函数定义的时候,小括号里面的变量
2.实参:函数再调用的时候,小括号里面的变量或者值
//声明定义函数的时候,a和b就是形参 function getMax(a,b){ if(a<b){ console.log(b); }else{ console.log(a); } } //调用函数的时候,传入的值,2和3就是实参 getMax(2,3);//3
3.形参个数和实参个数可以不一致
function getMax(a,b,c){ if(a<b){ console.log(b); }else{ console.log(a); } } getMax(2);//当传入的是一个值得时候,输出就是第一个参数a的值2 getMax(2,3);//形参多于实参,输出依然是3 getMax(2,3,4,5);//实参多于形参,输出也是3
三、return返回
1.return后面有内容,这个内容被返回了
function getSum(a,b){ return a+b; }; console.log(getSum(2,3));//5
2.类型:有参数有返回值/没有返回值,没有参数有返回值/没有返回值
常用:
//有参数有返回值 function getSum(a,b){ return a+b; }; console.log(getSum(3,4))//7 //有参数没有返回值 function sayHi(a){ console.log("这是我输入的语句:"+ a +"!") }; sayHi("今天天气真好");//这是我输入的语句:今天天气真好!
3.函数没有返回值,但是接收了,结果是undefined
function getSum(a,b){ var c=a+b; } console.log(getSum(2,4));//undefined
4.没有明确的返回值,即return后面没有内容,结果也是undefined
function getSum(a,b){ var c=a+b; return; } console.log(getSum(2,4));//undefined
5.return后面的代码不会执行
function getSum(a,b){ var c=a+b; return c; console.log("我在return的后面,不会执行了"); }; console.log(getSum(2,4));//6
6.有return最好设置定义一个变量去接受它,接收后这个变量就可以去进行其他操作,或者输出,或者进行运算等等
function getSum(a,b){ return a+b; ; } var result=getSum(10,20); console.log(result); //30
四、变量
1.全局变量:
- 声明的变量使用var声明,可以在页面的任何位置使用
- 除了函数以外,其他位置的变量都是全局变量
- 全局变量如果页面不关闭,就不会释放,站空间内存
var a=1;//全局变量 for(var b=2;b<2;b++){ //全局变量 console.log("哈哈"); } function f1(){ var c=1;//不是全局变量 }; console.log(a);//1 console.log(b);//2 console.log(c);//报错
2.隐式全局变量
- 声明的变量没有var 声明
- 隐式全局变量使用delete可以删除
- 全局变量使用delete不能删除
var a=10;//显式声明的全局变量 b=20;//隐式声明的全局变量 console.log(a);//10 console.log(b);//20 delete a; delete b; console.log(a);//10(依然可以输出,说明delete无效) console.log(b);//报错 console.log(typeof(b));//undefined
3.局部变量
- 在函数内部定义的变量,外面不能使用
function f1(){ var c=1;//局部变量 console.log(c); }; f1();//1 console.log(c);//报错
4.全局作用域和局部作用域
- 全局作用域就是全局变量的使用范围
- 局部作用域就是局部变量的使用范围
5.作用域链
- 函数变量是从本作用域开始寻找,从里到外
var a=10; function f1(){ var a=20; var b=a+a; return b; }; console.log(f1());//40
- 示意图
五、预解析
-
理解:在解析代码之前做的事,把变量的声明和函数的声明提前到当前所在作用域的最前面。
-
步骤:
- 把变量的声明提升到当前作用域的最前面,只提升声明,不会提升赋值
- 把函数的声明提升到当前作用域的最前面,只提升声明,不会提升调用
- 先提升var ,再提升function
//正常代码,没有预解析之前 f1();//前端good! function f1(){ var a="good!"; console.log("前端"+a); }; console.log(b);//undefined var b=10;
//上面的代码通过预解析之后会变成下面这样 var b;//var 变量声明提前 function f1(){ var a;//函数的声明提前,在当前作用域的最前面 a="good!"; console.log("前端"+a); };//函数的声明提前 f1(); console.log(b); b=10;
-
只有用函数声明方式定义的函数才会提升function,函数表达式定义的函数是一个变量,提升var
f1();//报错,因为预解析只提升了var f1;到上面 var f1=function(){ console.log("前端") };
-
变量和函数重名,执行函数(表达不准确,主要看代码)
var a; function a(){ console.log("前端大法好"); }; console.log(a);//输出上面的a函数,而不是undefined a=10; console.log(a);//10
-
如果有多对的script标签都有相同的名字的函数,
①如果函数是通过声明定义的,不会受影响
<script> function a(){ console.log("哈哈") }; </script> <script> a();//嘿嘿 function a(){ console.log("嘿嘿") };//函数声明会提前 </script>
②如果函数是通过函数表达式声明的,会受影响
<script> var a=function(){ console.log("哈哈") }; </script> <script> a();//哈哈 var a=function(){ console.log("嘿嘿") }; </script>
六、总结
1.argument
- 当做数组使用,是一种伪数组
- argument.length可以获取函数在调用传入的个数
function howManyArgs() { console.log(arguments.length); }; howManyArgs("string", 45);//2 howManyArgs();//0 howManyArgs(12);//1
- 使用argument[ " " ] 对象可以获取传入的每个参数的值
function f1(a,b,c,d) { console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); console.log(arguments[3]); console.log(arguments[4]); }; f1(1,2,3,4);//1 2 3 4 undefined
2.函数也是一种数据类型
- typeof检测出来的类型是function
function f1() { console.log("good!"); }; var f2 = function () { console.log("nice"); }; console.log(typeof(f1)); //function console.log(typeof(f2));//function
3.函数参数的类型
- 函数参数的数据类型可以是数字、字符串、布尔、数组等等
function f1(a){ console.log(a); }; f1(10);//参数是number f1("嘿嘿");//参数是string f1(1===2);//参数是Boolean f1([10,20,30,40]);//参数是Array var i=null; f1(i);//参数是null var j; f1(j);//参数是undefined
- 函数也可以作为参数使用,如果一个函数作为参数,那么这个参数(函数)就是回调函数
- 只要看到一个函数作为参数使用,就是回调函数
function f1(fn){ console.log("我是f1"); fn(); } function f2(){ console.log("我是f2"); } f1(f2);//我是f1 我是f2
//注意:是f1(f2),而不是f1(f2())
4.函数可以作为返回值使用
function f1(){ console.log("我是f1"); return function f2(){ console.log("我是f2"); } } f1();//我是f1 var ff=f1();//理解f1()是函数f1里面执行的内容,而f1是这个函数的整个表达式,定义一个变量去接受这个函数的调用 ff();//我是f1 我是f2
七、函数案列
//例1:m-n之间所有数的和 function getSum(m,n){ var sum=0; for(var i=m;i<=n;i++){ sum=sum+i; } return sum; } var result=getSum(1,100); console.log(result);//5050
//例2:圆的面积 function area(r){ return Math.PI*r*r } var result=area(3); console.log(result);//28.274333882308138
//例3:判断一个数是不是质数; function prime(num){ if(num==2){ return true; } for(var i=2;i<num;i++){ if(num%i!==0){ return true; }else{ return false; } } } var result=prime(6); console.log(result);//flase
//例4:两个数的最大值 function getMax(a,b){ return a>b?a:b } var result=getMax(2,3); console.log(result);//3
//例5:三个数的最大值 function getMax(a,b,c){ return a>b?(a>c?a:c):(b>c?b:c); } var result=getMax(2,5,4); console.log(result);//5
//例6:两个数的差 function differ(a,b){ return a-b; } var result=differ(6,3); console.log(result);//3
//例7:一组数中的最大值 function getArrayMax(arr){ var max=arr[0]; for(var i=0;i<arr.length;i++){ if(max<arr[i]){ max=arr[i]; } } return max; } var arr=[1,2,3,4,5]; var result=getArrayMax(arr); console.log(result);//5
//例8:一组数字的和 function getSum(arr){ var sum=0; for(var i=0;i<arr.length;i++){ sum=sum+arr[i]; } return sum; } var arr=[1,2,3,4,5]; var result=getSum(arr); console.log(result);//15
//例9:数组反转 function rev(arr){ for(i=0;i<arr.length/2;i++){ var temp=arr[i]; arr[i]=arr[arr.length-1-i]; arr[arr.length-1-i]=temp; } return arr; } console.log(rev([1,2,3,4,5]));//(5) [5, 4, 3, 2, 1]
//例10:冒泡排序(从大到小) function pup(arr){ for(var i=0;i<arr.length-1;i++) for(var j=0;j<arr.length-1-i;j++){ if(arr[j]<arr[j+1]){ var temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } return arr; } console.log(pup([1,5,3,7,4,9]))//(6) [9, 7, 5, 4, 3, 1]
//例11:阶乘和 function floor(num){ var sum=1; for(var i=1;i<=num;i++){ sum=sum*i } return sum; } var result=floor(5); console.log(result);//120
//例12:菲波那契数列 function rab(num){ num1=1; num2=1; sum=0; if(num==1||num==2){ sum=1; } for(var i=3;i<=num;i++){ sum=num1+num2; num1=num2; num2=sum; } return sum; } var result=rab(12); console.log(result);//144
//输入年月日,返回是这一年的第几天 function getDays(year, mouth, day) { var days = day; //如果月份是1月,直接返回天数 if (mouth == 1) { return days; } //如果月份是其他月,先定义数组,循环月份求和 var mouths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; for (i = 0; i < mouth - 1; i++) { days = days + mouths[i]; } //判断这一年是不是闰年,并且如果月份大于2,多一天 if (year % 4 == 0 && year % 100 !== 0 && mouth >= 2 || year % 400 == 0 && mouth >= 2) { days++; } return days; } var result = getDays(2018, 4, 25); console.log(result);//115