JS函数的概念
函数就是把特定功能的代码抽取出来,使之成为程序中的一个独立实体。
函数的作用
正如函数的概念, 我们可以根据需要, 将特定的功能用函数来包裹(封装)
使用函数的好处
- 函数可以在同一个程序或其他程序中多次重复使用(通过函数名调用)
- 使程序变得更简短而清晰 , 提高可读性
- 有利于程序维护
函数的分类
函数可以分为: 系统函数(内置函数) 和 自定义函数
系统函数(内置函数)
是官方提供好的函数,可以直接使用
alert(); //信息提示弹窗
var res = prompt("请输入一个数") //带有输入框的弹窗,res可接收输入的值
var res = confirm("您确定要删除吗?");//确认框,res接收true或false
print();//打印页面
document.write();//将内容写入前端页面
console.log();//将内容输出到控制台
isNaN();//是否为非数值类型
parseInt();//转换为整型
parseFloat();//转换为浮点型
Number();//转换为数值类型
Boolean();//转换为布尔类型
toString();//转换为字符串
toFixed();//保留小数点后几位 四舍五入
// ...
自定义函数
是用户自己定义的函数, 用户可以根据实际需求, 对特定的功能使用函数来封装
函数的定义有三种写法:普通写法、匿名函数和构造函数创建函数
函数定义及调用——普通写法
定义函数的语法格式:
function 函数名([形参1,形参2,……]) {
代码块;
}
调用函数的语法格式:
函数名([实参1,实参2,……])
function calc(num1, num2) {
var res = num1 + num2;
return res;
}
var result = calc(100, 200);//可以在定义函数的前面或后面调用
console.log(result);
函数定义及调用——匿名函数
定义函数的语法格式:
var 变量名 = function([形参1,形参2,……]) {
代码块;
}
调用函数的语法格式:
变量名([实参1,实参2,……])
var calc = function (num1, num2) {
var res = num1 + num2;
return res;
}
var result = calc(100, 200);//必须在在定义函数后面调用
console.log(result);
函数定义及调用——构造函数创建函数
定义函数的语法格式:
var 变量名 = new Function([形参1,形参2,……],代码块);
调用函数的语法格式:
变量名([实参1,实参2,……])
// new Function的最后一个参数,是函数的代码体
var calc = new Function("num1", "num2", "return num1+num2");
var result = calc(100, 200);//必须在在定义函数后面调用
console.log(result);
函数中的arguments数组
JS中函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型,在调用函数时也未必一定要传递指定数量的参数,原因是 ECMAScript 中的参数在内部是用一个数组(arguments)来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。
arguments 参数
1.它是一个伪数组,有下标,不具备数组的方法
2.它只能在函数内部出现
作用:动态接受实参
// 例,写个函数计算所有传入参数相乘的结果(参数数量不定)
function fn1(){
var res=1;
for(var i=0;i<arguments.length;i++){
res*=arguments[i];
}
return res;
}
console.log(fn1(1,2,3));//6
console.log(fn1(1,2,3,4));//24
console.log(fn1(1,2,3,4,5));//120
作用域
作用域: 就是起作用的范围,或者说有效范围。
1).变量在函数内部的是局部的
2).变量在函数外部的是全局的
作用域链:当函数内部访问某一个变量的时候,首先去函数内部查找,如果内部没有,就向外层函数查找,如果外层函数,没有就向(浏览器向window)全局在nodejs是向(global)上查找,这个"查找的过程"就叫做"作用域链"。
var a=100;//全局变量a
var c=150;//全局变量c
function fn1(a){//局部变量a
a=50;//改变的是局部变量a
var b=200;//局部变量a
console.log(a);//50
console.log(c);//150
console.log(b);//200
}
fn1();
console.log(a);//100
console.log(c);//150
console.log(b);//报错 b is not defined 这个地方已经超过了变量b的有效范围无法调用
局部变量
局部变量定义在函数内部的变量,这个变量只能在函数内部使用,即作用域范围只是函数内部,另外,形参也是局部变量。
function fn(){
var a=100;
console.log(a);//100
}
fn();
console.log(a);//找不到变量a,因为a是在函数内部定义的局部变量,会报错 a is not defined
全局变量
全局变量就是定义在函数外部的变量,这个变量在任何函数中都有效,即作用域范围是当前文件的任何地方。
【注意】: 在定义变量时, 如果不写关键字var也是合法的, 且是全局变量, 但是这样写不安全,容易在其他地方被更改, 所以我们在函数中写变量要加上var
function fn() {
//在函数内部,使用var关键字,声明的变量是局部变量
//在函数内部,没有使用var关键字,声明的变量是全局变量
var a = b = 100;
console.log(b);//100
console.log(a);//100
}
fn();
console.log(b);//100
console.log(a);//报错 a is not defined
函数嵌套
函数的嵌套: 函数内部可以再包含其他函数;
函数之间允许相互调用,也允许向外调用, 但是不可以调用同级函数的嵌套函数;
function fn1() {
console.log("-----------");
console.log("函数1");
//函数之间相互调用
fn2();//函数2
//不可以调用同级函数的嵌套函数
fn3();//报错 fn3 is not defined
}
var flag=true;//设置一个让内部的fn3只能调用一次fn2的变量
function fn2(){
console.log("-----------");
console.log("函数2");
//函数内部可以再包含其他函数
function fn3(){
console.log("函数3");
if(flag){
flag=false;//修改为false后不再会进入此代码块,没有这一句将会是死循环
//函数向外调用
fn2();//函数2
}
}
fn3();
}
fn2();
fn1();
控制台输出:
递归调用
函数可以自己调用自己,必须要有结束条件(有临界点),称为函数的递归调用
递归调用的方式
- 首先去找临界值,即无需计算,获得的值(一般是返回该值)。
- 找这一次和上一次的关系(一般从后往前找)
- 假设当前函数已经可以使用,调用自身计算上一次的运行结果,再写出这次的运行结果。
例题一 5的阶乘是多少?
function fn(n) {
if (n == 1) {
return 1;
}
return n * fn(n - 1);
}
console.log(fn(5));
例题二 兔子繁殖问题
// 兔子繁殖问题,设有一只新生兔子,从第四个月开始他们每个月, 月初都生一只兔子,
// 新生的兔子从第四个月月初开始又每个月生一只兔子按此规律,并假定兔子没有死亡,
// n(n<=20)个月月末共有多少只兔子?
// 月份 1个月大小 2个月大小 3个月大小 4个月大小 总计
// 1 1 0 0 0 1
// 2 0 1 0 0 1
// 3 0 0 1 0 1
// 4 1 0 0 1 2
// 5 1 1 0 1 3
// 6 1 1 1 1 4
// 7 2 1 1 2 6
// 8 3 2 1 3 9
// 9 4 3 2 4 13
// 10 6 4 3 6 19
// .
// .
// 20 ?
//临界条件 n<4
//规律:fn(n)=fn(n-1)+fn(n-3)
function fn(n){
if(n<4){
return 1;
}
return fn(n-1)+fn(n-3);
}
console.log(fn(20));//872