# 函数
函数是实现功能的载体, 它应该是一个最小功能的封装, 比如我们要计算两个数之和,再比如我们要实现计算正方形的体积等等。
# 函数定义和调用
# 函数定义
我们使用 function 关键字定义函数
// demo 为函数名, 自己命名但必须符合JS标识符命名规则
// () 小括号中可以带参数, 这种参数还有个称呼 叫做 形式参数 简称形参 。 形参可以省略,但小括号不能省
// {} 大括号内部的函数就是逻辑运算部分, 如果我们要计算 传入的 a、b 的和,就可以在这里写
function demo(a, b){
// 函数的主题内容
}
# 函数调用
我们希望在哪里执行定义的函数, 就在哪里进行调用。
// 函数调用,写清楚函数名称,已经调用的参数
demo(2, 3);
从函数定义中,我们可以看出函数总共由三部分构成, 输入、输出和计算
输入告诉我们外部的一些变量值,然后通过计算把结果输出
# 输入
输入传的值,我们也叫形参,即形式参数,意思是我们还不知道具体传什么值,先拿一个变量占上坑。如函数定义中的 a, b 两个参数
当我们具体调用的时候才会确定要传什么值, 这时候的参数叫做实参(实际参数)
// 传入 2, 3 在函数运算的时候会替换掉 形参, 所以我们叫他们实参
demo(2, 3);
形参 和 实参 有时候数量并不相等,不等情况有两种
- 形参比实参多
<script>
function print(a, b , c) {
console.log("a=", a,",b=",b,",c=",c);
}
// 形式参数 定义了三个 a, b ,c 但此时之传入了两个, 则 1赋值给 a , 2赋值给b , c 只能为 undefined了
print(1, 2)
</script>
- 实参比形参多
<script>
function print(a, b , c) {
console.log("a=", a,",b=",b,",c=",c);
}
// 形式参数 定义了三个 a, b ,c , 但是我们没有形参接受4 这个实际传入的参数,这个参数在这个运算中只能被抛弃
print(1, 2, 3,4)
</script>
实际需求中我们应该能准确的使用函数,使得形参和实参一一对应
但有时候,又有一些场景,我们想在被调用的函数中能够获取到所有传入的实际参数。比如:求传入的所有实参的和。
这种场景,需要 arguments, arguments 能够像数组那样遍历,获得所有实参
<script>
function plus() {
var resultPlus = 0;
for(var i = 0 ; i < arguments.length ; i++) {
resultPlus += arguments[i];
}
return resultPlus;
}
var result = plus(1,2,3,4,5)
console.log(result);
</script>
# 输出
从函数定义的例子当中,我们并没有看到输出,即函数并没有返回任何结果
这是因为在一个函数中,可以没有输入、也可以没有输出、甚至也可以把函数计算也拿掉(空函数, 当然这种函数没有任何现实意义)
如果我们函数运算完成后需要返回值怎么办?
好办,用 return 关键字, 举个栗子,我们想计算 两个数的和,并返回计算结果, 代码如下
<script>
function plus(a, b){
return a + b;
}
</script>
如果代码能执行到return语句就意味着函数运行结束了, 它会把代码的执行权先归还给调用者
# 匿名函数
以上的例子中,函数都有名字;我们改造下, 就会得到匿名函数,匿名函数就是没有名字的函数
function(a,b) {
// 函数主体内容
}
如果我们把上面的函数运行在浏览器,肯定会报错, 因为任何函数定义出来都是要调用执行的,上面定义的函数报错就是因为浏览器不知道如何运行引起的
所以这么写是不完整的, 根据需要,我们可以用以下的思路定义匿名函数
将匿名函数赋值给变量
var fun = function(a, b) {
//
}
这样,我们的函数居然又拥有了一个“名字”
当然函数的调用的写法不变
fun(a,b);
用小括号包裹
<script>
(function (a,b ){
console.log('hello', a,b)
})
</script>
这种方式只是定义,我们无法在其他地方调用它,同样也无法执行, 这貌似打破了我们上面说的:一个函数定义出来就是要调用执行的说法
所以为了把这句话圆回去,我们必须加点东西,我们再加一个小括号,把它变成立即执行函数;也就是说我们在函数定义的地方调用它,当浏览器解析到此代码的时候立即执行。
<script>
(function (a,b ){
console.log('hello', a,b)
})();
</script>
立即执行函数,既保证了在定义的地方可以调用,也保证的 任何函数都需要调用执行的说法
回调函数
函数还可以作为一个参数值传给其它函数, 其它参数执行到具体代码会自动调用。
我们上一篇
数组
紫薯自书,公众号:优雅编程JS基础-复杂数据类型之数组 (opens new window)
提到的排序的例子,就是把一个函数当作形参传入到了另外函数中
var sortArray = array.sort(function(a, b){
return b-a;
});
把函数当成一个返回值
函数还可以当成返回值返回给调用方
<script>
function plus(a, b){
return function() {
return a + b;
}
}
var plusResult = plus(1,2);
var plusResultFunResult = plusResult();
console.log(plusResult);
console.log(plusResultFunResult);
</script>
上面这个例子, plus 函数返回了一个函数给调用方
plusResult 指向的是一个函数
plusResultFunResult 指向的才是最终的运算结果
如果我们只想得到结果,省略啰嗦的函数赋值给引用变量的过程,我们也可以像下面一样这么做
<script>
function plus(a, b){
return function() {
return a + b;
}
}
var plusResultFunResult = plus(1,2)();
console.log(plusResultFunResult);
</script>
# 函数的执行顺序
一个函数执行的顺序,是从调用开始, 逐行开始执行,直到遇见return或者函数最后一行结束。最终函数执行结束后会把调用权交还给函数。
# 函数的声明提升
和变量的声明提升类似,函数可以被提升
fun();
function fun() {
console.log("函数执行了");
}
如果函数使用函数表达式的写法定义的,则没有提升特性
fun(); //引发错误
var fun = function(){
alter("函数被执行");
}