文章目录
前言
这部分来学习函数的知识,要做到学以致用啊!
一、函数
函数,也叫作功能、方法,可以将一段代码封装起来,封装起来的代码具有一定的功能,内部封装的代码具有完整的结构体,要执行就都执行,要不就都不执行。(作用:封装一段代码,将来可以重复使用)。
1.函数的声明和调用
函数的声明又叫做函数的定义,先定义才能使用。函数调用:函数名() ,函数内部语句执行的位置,与定义位置无关,与调用位置有关。
//声明函数
function fun() {
console.log(1);
console.log(2);
console.log(3);
console.log(4);
}
console.log(5);
//调用函数
fun();
2.函数的参数
接口:就是函数的参数,函数参数的本质就是变量,可以接收任意类型的数据,导致函数执行结果根据参数不同,结果也不同。
一个函数可以设置0个或者多个参数,参数之间用逗号分隔。
形式参数:定义的()内部的参数,叫做形式参数,本质是变量,可以接收实际参数传递过来的数据。简称形参。
实际参数:调用的()内部的参数,叫做实际参数,本质就是传递的各种类型的数据,传递给每个形参,简称实参。
代码如下(示例):
//定义一个求和函数。函数里面传入两个数据
//参数:传入两个参数,数据类型为数字
//功能:得到两数之和
function sum(a,b) {
console.log(a+b);
}
//调用函数,括号内添加数据。
sum(5,7);
sum("3",7);
3.函数的返回值
函数能够通过参数接收数据,也能将函数的执行结果返回一个值。利用函数内部的一个关键字return设置函数的返回值。
函数如果有返回值,执行结果可以当成普通数据参与程序。函数如果有返回值,可以作为一个普通数据赋值给一个变量,甚至赋值给其他函数的实际参数。
注意:如果函数没有设置return语句,那么函数有默认的返回值undefined;如果函数使用return语句,但是return后面没有任何值,那么函数的返回值也是 undefined。
代码如下(示例):
//定义一个求和函数。函数里面传入两个数据
//参数:传入两个参数,数据类型为数字
//功能:得到两数之和
function sum(a,b) {
return a+b;
}
//调用函数
console.log(sum(5,7));
//把函数的返回值赋给一个变量
var he = sum(2,4);
console.log(he);
//把函数的返回值赋给一个函数
console.log(sum(2,sum(3,4)));
//return可以终止函数执行
// function fun() {
// console.log(1);
// console.log(2);
// console.log(3);
// return;
// console.log(4);
// }
// fun();
4.函数表达式
函数表达式是定义函数的另一种方式,就是将函数的定义、匿名函数(函数没有函数名)赋值给一个变量。
//定义一个函数表达式
var gai = function fun() {
console.log(1);
};
var gai2 = function() {
console.log(2);
};
//调用的时候,调用函数名不成功,只能调用变量名加括号。
// fun();
gai();
gai2();
5.函数的数据类型
函数是一种数据类型,是function(属于object),可以作为其他函数的参数,将函数当成另一个函数的返回值。
function fun() {
console.log(1);
}
var gai = function() {
console.log(2);
}
//检测函数的数据类型
console.log(typeof(fun));
console.log(typeof(gai));
//函数是一种数据类型,可以作为其他函数的参数
setInterval(function() {
console.log(1);
},1000);
//将函数当成另一个函数的返回值
function di(a) {
var b = 3;
return function() {
alert(a+b);
};
}
6.arguments对象
arguments对象是一个比较特别的对象,实际上是当前函数的内置属性,也就是所有函数都内置了arguments对象,arguments存储了所有的实参,是一个伪数组,可以进行遍历。
function sum(a,b) {
return a+b;
}
//实参的个数可以与形参的个数不一样
console.log(sum(1,2));
console.log(sum(1));
console.log(sum(1,2,3,4));
//arguments可以接收所有的实参
function fun() {
console.log(arguments);
console.log(arguments.length);
//遍历数组内的实参
for (var i = 0 ;i < arguments.length ;i++) {
console.log(arguments[i]);
}
}
fun(1,2,3,4,5,6);
案例
定义一个求和函数,如果传入1个参数,返回它自己,如果传入两个参数,返回他们的和,如果传入三个参数,先比较前两个的大小,大的与第三个参数求和返回,如果传入4个及以上,输出错误提示。
function sum(a,b,c) {
//条件分支语句,根据实参的个数不同来判断分支
switch (arguments.length) {
case 1:
return a;
break;
case 2:
return a + b;
break;
case 3:
return a > b ? a + c : b + c;
break;
default:
//模拟控制台报错
throw new Error("参数不能超过三个!");
}
}
//调用函数
console.log(sum(1));
console.log(sum(1,2));
console.log(sum(1,2,3));
console.log(sum(1,2,3,4,5));
7.函数的递归
函数的内部可以通过函数名调用函数自身的方式,就是函数的递归现象。(递归的次数太多容易出现错误,超出了计算机的计算能力)
//函数,如果传入的参数是1,那么返回1,如果输入的是其他数,那么返回参数+函数调用上一项
function fun(a) {
if (a === 1) {
return a;
} else {
return a + fun(a-1);
}
}
console.log(fun(1));
console.log(fun(2));
console.log(fun(3));
console.log(fun(4));
// console.log(fun(100000000000));
斐波那契数列案例
//斐波那契数列
//参数:正整数
//返回值:对应正整数位置的菲波那切数列
function fibo(a) {
if (a ===1 || a === 2) {
return 1;
} else {
return fibo(a-1) + fibo(a-2);
}
}
//调用函数
console.log(fibo(1));
console.log(fibo(2));
console.log(fibo(3));
console.log(fibo(4));
二、作用域
作用域:变量可以起作用的范围。
如果变量定义在一个函数内部,只能在函数内部被访问到,在函数外部不能使用这个变量,函数就是变量定义的作用域。
局部变量:定义在函数内部的变量,只能在函数作用域内部被访问到,在外面没有定义的。全局变量:从广义上来说,也是一种局部变量,定义在全局的变量,作用域范围是全局,在整个js程序任意位置都能够被访问到。
var a = 0;
//定义一个函数
function fun() {
var a = 1;
console.log(a);
}
//调用函数
fun();
console.log(a);
1.参数和函数的作用域
函数的参数本质是一个变量,也有自己的作用域,函数的参数也是属于函数自己内部的局部变量,只能在函数内部被使用,在函数外面没有定义。
函数也有自己的作用域,定义在哪个作用域内部,只能在这个作用域范围内被访问,出了作用域不能被访问的。
函数定义在另一个函数内部,如果外部函数没有执行时,相当于内部代码没写。
//函数的参数是局部变量
function fun(a) {
var a = 1;
console.log(a);
}
fun(1);
// console.log(a);
// 函数也有自己的作用域
function outer() {
var a = 1;
function inner() {
console.log(2);
}
inner();
}
outer();
// inner();
2.作用域链和遮蔽效应
作用域链:创建一个函数就会有一个新的作用,如果函数中还有函数,那么这个作用域中就还有作用域。函数内指向函数外的链式结构就是作用域链。
遮蔽效应:程序在遇到一个变量时,使用时作用域查找顺序,不同层次的函数内都有可能定义相同名字的变量,一个变量在使用时,会优先从自己所在层作用域查找变量,如果当前层没有变量定义会按照顺序从本层往外依次查找,直到找到第一个变量定义。整个过程中会发生内层变量遮蔽外层变量的效果,叫做“遮蔽效应”。
//定义一个全局变量
var a = 1;
//定义一个外层函数
function outer() {
var a = 2;
//定义一个内层函数
function inner() {
var a = 3;
console.log(a);
}
inner();
}
outer();
三、其他
1.不写var关键字的影响
在函数内部想要定义新的变量,如果不加关键字var,相当于定义的全局变量。如果全局也有相同的标识符,会被函数内部的变量影响,局部变量污染全局变量。
注意:每次定义变量时都必须写var关键字,否则就会定义在全局,可能污染全局。
2.预解析
1.把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值
2.把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用.
3.先提升var,再提升function。
提升过程中,只提升声明过程,不提升变量赋值,相当于变量定义未赋值,变量内存储undefined值。
在预解析过程中,所有定义的函数,都会将声明的过程提升到所在的作用域最上面,仕将来的代码执行过程中,按照先后顺序会先执行被提升的函数声明过程。
在预解析之后的代码执行过程中,函数定义过程已经在最开始就会执行,一旦函数定义成功,后续就可以直接调用函数。
因此,在js 中会出现一种现象,在前面调用后定义的函数,不会报错,而且能正常执行函数内部的代码。
函数声明提升可以用于调整代码的顺序,将大段的定义过程放到代码最后,但是不影响代码执行效果。
//预解析,把变量函数声明提升到了最顶部
console.log(a);
var a = 1;
fun();
function fun() {
console.log(3);
}
3.IIFE自调用函数
叫做即时调用的函数表达式,表示函数定义时就调用。如果能将函数矮化成表达式,那么后面加上()就可以立即执行。
函数矮化成表达式的方法,可以让函数参与一些运算,也就是说给函数前面加一些运算符。
数学运算符:±()
逻辑运算符:!非运算
lIFE结构可以关住函数的作用域,在结构外面是不能调用函数的。lIFE最常用的是()运算符,而且函数可以不写函数名,使用匿名函数。
//关键字定义的函数方式,不能立即执行
function fun() {
console.log(1);
}
//函数表达式方式,可以在定义时立即执行
var foo = function() {
console.log(2);
}();
//通过在函数前面添加操作符,可以将函数矮化成表达式
+ function fun() {
console.log(3);
}();
- function fun() {
console.log(4);
}();
( function fun() {
console.log(5);
} )();
! function fun() {
console.log(6);
}();
//IIFE关住了函数作用域,在外面是调用不函数的,这样只能自调用一次。
fun();
//常用的IIFE结构
( function fun(a) {
console.log(a);
} )(4);
总结
函数这部分就学习完了,下一部分学习对象,JavaScript在前端里面是很重要的一个模块,一定要多多练习啊。