函数
定义
函数主要用于对具体某些功能或方法的代码块进行打包或封装
特点
- 函数不会主动调用,使用时需要手动调用
- 函数可以被多次调用
- 每个函数就是一个短小的脚本
作用
-
减少代码冗余
-
方便后期的开发及维护
-
函数可以被多次调用
-
函数真正的威力体现在,允许将不同的数据传递给函数。
在js中共两种函数
-
自定义函数
在这主要讨论自定义函数。 -
系统函数(内置函数)
- js中已经定义好的函数,使用时,不需要定义,直接使用即可
- 强制转换数据类型的
String()
,Number()
,Boolean()
,paresInt()
,parseFloat()
-
isNaN()
判定 值,如果不是数字返回true
,如果是数字返回false
;主要用于判定程序中的某些值是否是合法值 -
eval()
表示把字符串转换为表达式,一般不使用此方法。
自定义一个函数
就是如何封装一个功能或方法,可以分为三个步骤
- 确认函数的名称
- 确认参数个数
- 确认是否需要有返回值(
return
)
下面是具体的方法与细节理解
1.定义函数
定义函数有两种方式
1.1 函数的声明式
通过关键字function
function 函数名(){
//功能代码
}
函数命名规则
- 使用字母(大小写),数字,$,但是数字不能开头,且不能包含空格。
- 在命名变量名时使用下划线来分隔各个单词,为了一眼看出是函数名还是变量名,函数名使用小驼峰命名。
- 不能使用中文,尽量使用相关功能的英文名称
- 函数名有多个单词组成,使用驼峰命名法
1.2 函数的表达式
- 函数是一种引用数据类型,只要是数据就可以赋值给变量,此时的变量就是函数名,通过函数名()即可调用该函数。
var 变量名 = function(){
//功能代码
};
function
( ){ 代码块 }
表示匿名函数,没有函数名称的函数,此时的变量名就是函数名。
2.调用函数
函数定义好后,函数不会自己执行,必须手动调用。使用如下语句调用
函数名( );
其中( )
表示执行指定函数
注意
写一个函数的过程一般是先进行需求分析,再确定函数名,再进行函数的功能或方法的代码书写,以及封装,最后写完不要忘了调用,不调用,函数是不会自动执行的。简单来说,就是函数的定义和调用两个步骤。
针对两种定义函数都可以用,但是也有一些区别值得注意
3.两种定义函数的区别知识点
-
对第二种表达式定义函数的理解。函数是一种引用数据类型(与基础数据类型对应的常见引用数据类型有对象,函数,数组),只要是数据就可以赋值给变量,此时的变量就是函数名。
-
两种定义方式在调用与定义顺序的区别。使用申明式定义的函数,调用可以放在函数的前面或者后面,前后效果一样。但是函数的表达式,只能在定义函数的后面调用。因为赋值给了变量,变量的使用就是先申明再使用。
在声明式定义的函数的脚本里,可以从任意位置去调用这个函数。
- 两种方式定义的函数的共同点。都可以多次调用,调用一次执行一次。
4.参数(argument)
在上面提到函数真正的威力体现在,允许将不同的数据传递给函数。我们可以把传递给函数的数据称为参数(argument)。函数的参数分为形参和实参。
4.1 形参
形式参数,即形参。函数在执行过程中需要进行数据的计算,但是该数据不是具体的某个值,使用形参代替。类似数学表达式的的自变量,需要给自变量给定某个值才有结果,但是需要这个变量在这占位置。有了这个位置才能接受给定的值进行计算。
形式参数相当于函数体中的定义的变量,只是一个占位符。相当于在函数体内var 形参 ;
但是未赋值一样。
在定义函数的时候,可以为它声明任意多个参数,只要用逗号将它们分隔开就行。在函数体内部可以像使用普通变量那样使用它的任何一个参数。
如
function 函数名字(形式参数1,形式参数2,....){
功能代码…
}
var 变量名 = function(形式参数1,形式参数2){
功能代码…
}
4.2 实参
函数名(实参1,实参2,....);
实际传入的参数与形式参数必需一一对应,但是在js中,形参的个数和实参的个数可以不相等,也不会报错,如果,实参多了,那么忽略多的,前面的一一对应。如果形参多了,那么,多的就是未定义,就是申明了变量但是未赋值的时候的未定义。
5. 函数返回值
函数不仅可以以参数的形式接收数据,还可以返回数据。
创建了一个函数,想让函数返回一个数值、一个字符串、一个数组或一个布尔值。这个时候就要用到
return
语句。
程序在执行中产生的数据可能会被其他程序使用,或者计算结果会参与其他的运算,这时候必须使用return
作为返回相应的值,不然返回的是undefined
。如果直接使用函数赋值给一个变量,变量与一个数字相加,返回的是NaN
。
函数真正的价值体现在,可以把函数当做一种数据类型来使用,可以把一个函数的调用结果赋给一个变量。
返回值的语法结构
申明式
function 函数名( ){
函数体;
return 结果值;
}
- 如果程序中的计算结果需要在外部使用,必须使用
return
进行返回。 - 如果程序的计算结果不需要参与外部的运算,可以使用三种输出方式输出即可。
-
如果需要返回多个值,需要使用数组或对象的方式来保存数据。
a. 数组 [a, b, c]
b. 对象 [key:value; ]
在递归函数中的应用
斐波拉契数列
<script>
function f(n) {
if (n == 0 || n == 1) {
return 1;
}else {
return f(n-1)+f(n-2);
}
}
document.write(f(2));
</script>
阶乘
<script>
function fact(n) {
if (n == 0 || n == 1) {
return n;
} else {
return fact(n-1)*n;
}
}
document.write(fact(3));
</script>
前n项奇数和
<script>
function oddSum(n) {
if (n == 1) {
return 1;
}else{
return 2*n - 1 + oddSum(n-1) ;
}
}
document.write(oddSum(10));
</script>
return表示返回值,且终止此次代码。
6. 变量的作用域(scope)
变量的作用范围
函数体内定义的变量为局部变量
函数体为未使用关键字的变量为隐式全局变量
- 确定变量的作用范围
- 根据变量声明的位置可以分为全局变量和局部变量
6.1 全局变量
主要声明在函数外部,供整个js代码使用。
如果使用同一个名字的变量,可能会冲突。
6.2 局部变量
主要在函数内部通过var
关键字声明的,仅供当前函数使用。
局部变量的优先级高于全局变量。
6.3 建议
针对变量的作用域给的建议
函数在行为方面应该像一个自给自足的脚本,在定义一个函数时,我们要把它内部变量全都明确的申明为局部变量。
尽量不要在函数体内不使用关键字直接使用一个变量,虽然不会报错,如果变量名和外部的变量名一样,那么函数体的变量会提升变量为全局变量,会影响到外部的变量的值。
如果总是在函数体里使用关键字来定义变量,就能避免任何形式的二义性隐患。
6.4 用途
当然了解了变量的作用域,可以用于以下
- 主要用于团队开发时,避免变量名的冲突
- 一般团队开发,先使用局部变量,后期合并代码时,再抽取公用变量。
7. 递归
上文提到了递归,递归用一句话说,即函数自身对自身的调用
递归函数必须有1.递归点和2.递归出口
递归点,表示什么时候开始调用自己(递进去)
递归出口,表示什么时候不再调用自己(归回来)
注意
- 递归函数必须有出口,没有出口则为死循环。
- 递归函数必须要有层次的变化
用途
- 主要用于后期大型项目中的树形结构的遍历如商品分类(无限极),文件目录查找,排序算法,QQ克隆好友操作。
经典的递归例子,斐波拉契数列,基于斐波拉契数列的还有一个经典例子,跳台阶。
所有的递归函数都可以用循环的语句写出来,但是递归有递归的优点,当然也有其缺点。
递归的缺点,占很大的内存。
网友评论