分享学JavaScript的第五天

一.初步了解函数

1. 函数的定义和调用
1.1 函数定义

函数其实就是将多条语句,组合成一个“语句军团”,集体作战。

//定义一个函数,函数就是一组语句的集合
function fun(){
    console.log(1);
    console.log(2);
    console.log(3);
    console.log(4);
}

//调用函数
fun();

函数必须先定义然后才能调用.

定义一个函数,用关键字function来定义,

function后面有一个空格,后面就是函数名字,函数的名字也是标识符,

既然是标识符,那么命名规范和变量命名就是一样的。

定义一个函数,也叫声明一个函数:

function 函数名(){

}

函数如果不调用,那么里面的语句就一辈子不会执行,不调用就等于白写。

1.2 函数调用

调用一个函数的方法非常简单,函数名后面加一个() ,

() 是一个运算符,表示执行一个函数。

执行函数:

函数名()

一旦调用了函数,函数内部的语句就会执行。

2. 函数的参数
2.1 参数的了解

可以通过参数让函数内部的语句有所不同

定义函数的时候,内部语句可能有一些悬而未决的量,就是变量,这些变量,我们要求在定义的时候都罗列在小括号中:

比如:

function fun(num){
	console.log("这已经是我第" + num + "次说爱你们了,我哭了,你们呢?");
}

调用的时候,要把这个变量的真实的值,一起写在括号里,这样随着函数的调用,这个值也传给了num:这就是参数传递

执行这个函数:

fun(99);

罗列在function小括号中的参数,叫做形式参数;

调用时传递的数值,叫做实际参数。

形式参数就像占位置,先把位置站好,等你来赋值

2.2 参数个数

参数可以有无数个,用逗号隔开。

//有多少形式参数都可以,都罗列出来
function fun(a,b){
    console.log(a + b);
}

fun(2,6);	//输出8
fun(6,18);	//输出24

定义函数的时候,不需要指定类型:

function sum(a,b){
	console.log(a + b);
}

也就是说调用的时候,传进去值是什么类型,就是形参a、b就是什么类型

sum("5",20);

输出520,做的是连字符的运算。

2.3 实参和形参个数不等

我们可以发现,声明函数的时候和调用函数的时候参数个数可以不一样多,也不报错。

  • 实参个数小于形参个数
sum(20);          //NaN

因为我们只传了一个参数,b就没有传递,b被隐式的var了,所以值undefined。10+undefined就是NaN

也就是说没有实参传递的形参是undefined.

  • 实参个数大于形参个数
sum(10,20,32,23,22,2,4);   // 30

只有前两个参数被形参接收了,后面的参数无视了,

也就是说,形参会按顺序接收实参,多余的实参,没人接收,也就不了了之了

2.4. arguments

每个函数里面都有一个隐式的arguments这个是系统以及给你创建好的,每个函数内部都有,arguments是类似于数组的类数组.就是实参列表

类数组本质上是一个对象,什么是类数组先不用管,先把他当成一个数组,涵盖了所有实参。

调用函数的时候,比如:

fun(45,43,57,347,223,162);

此时函数内部,arguments就有一个下标,就依次等于上面调用的数:

arguments[0]  // 45
arguments[1]  // 436
……
arguments[5]  //12

如果函数里面有形式参数列表,那么是和arguments同步的:

function fun(a,b){
    arguments[0] = 8;   //改变了第一个参数的值
    alert(a);		//8  ,弹出改变后的值
    
    console.log(arguments.length);  // 实参的长度
    console.log(fun.length);        // 形参的长度
}

fun(45,43,57,347,223,162);

arguments的功能,是模拟函数的重载,使得同一个函数,根据参数个数的不同,有不同的作用。

3. 返回值

函数可以通过参数来接收东西,更可以通过return的语句来返回值,“吐出”东西。

function sum(a,b){
    return a + b;		//现在这个函数的返回值就是a+b的和
}

console.log(sum(5,4));  //sum没有输出功能,就要用console.log输出
//sum(5,4)实际上就成为了一个表达式,用来计算结果
//计算后就是9,相当于console.log(9);

函数只能有唯一的return,有if语句除外,因为if是分支语句

程序遇到了return,将立即返回结果,返回调用它的地方,而函数内return后面的语句将不在执行。

function fun(){
    console.log(1);
    console.log(2);
    return;			   //返回一个空值
    console.log(3);  //这行语句不执行,因为函数已经return了,所以不会打印3
}

fun();    //1, 2
3.2 函数作为参数使用

函数有一个return的值,那么现在这个函数,实际上就是一个表达式,换句话说这个函数调用完成后整体就是一个值。

所以这个函数,可以当做其他函数的参数。

sum(5,sum(5,2));       //12

程序是先执行内层在执行外层.

函数可以接受很多值,返回一个值,

函数的意义

  1. 在出现大量程序相同的时候,可以封装为一个function,这样只用调用一次,这样只要写一次代码就可以调用多次,减少代码耦合。
  2. 我们在调用一个函数的时候,不用关心函数内部的实现细节,只要可以运用。并能给给我们团队开发带来了好处。
  3. 模块化编程,让复杂的逻辑变得简单。
4. 递归

函数内部又调用了函数自身,我们把这种情况叫做递归

斐波那契数列就是经典的递归算法:

1、1、2、3、5、8、13、21、34、55、89、144、233……

输出斐波那契数列

欣赏,对于一个搞前端的来说,没必要把程序学这么深:

//1、1、2、3、5、8、13、21、34、55、89、144、233……
//只需要一个函数,就可以搞定全部问题
//fib(n) 就能得到第n位的数字
//fib(2) = 1
//fib(5) = 5
//fib(6) = 8
//fib(10) = 55

function fib(n){
    if(n == 1 || n == 2){
        return 1;
    }else{
        return fib(n - 1) + fib(n - 2);
    }
}

//一点一点计算:
for(var i = 1 ; i <= 55 ;i++){
    console.log(fib(i));
}

二. 函数表达式

定义函数除了使用function之外,还有一种方法,就是函数表达式。就是函数没有名字,称为“匿名函数”,为了今后能够调用它,我们把这个匿名函数,直接赋值给一个变量。

var sum = function(a,b){
	return a + b;
}

以后想调用这个函数的时候,就可以直接使用sum变量来调用。

console.log(sum(3,6));

如果现在这个函数表达式中的function不是匿名的,而是有名字的:

var sum = function fun(a,b){
    return a + b;
}

那么JS表现非常的奇怪,在外部只能用sum()来调用,fun()会引发错误!

也就是说,JS这个奇怪的特性,给我们提了个醒,定义函数,只能用这两种方法中的其一,不建议杂糅:

第一种,通过函数声明定义函数

function sum(){
    
}

第二种,通过匿名函数的赋值定义函数

var sum = function(){
    
}

建议不要混用,这么写也不算错

var xixi = function haha(){
}

三. 函数声明的提升

JS在执行前,会有一个预解析的过程,把所有的函数声明,都提升到了最最开头,然后再执行第一行语句。

所以,function定义在哪里,都不重要,程序总能找到这个函数。

//先调用
fun();	
//然后定义
function fun(){
	console.log("我是函数,我执行了!");
}

不会引发错误,打印能够正常执行。

1. 声明函数和函数表达式提升方式不同

函数声明会被提升,但是函数表达式却不会被提升

函数表达式提升的是变量,变量提升后并不是一个函数,所以在表达式之前执行,会报错,为类型错误,因为不是函数.

fun();  //报错
var fun = function(){
    alert("我是函数,我执行了!");
}

这提了个醒,没有极特殊的理由,都要使用function 关键字来定义函数,而不要使用函数表达式来定义函数.

1.1.函数优先
sum();	//现在这个sum到底是函数,还是变量8呢?
//函数优先,遇见同名标识符,预解析阶段一定把这个标识符给函数

var sum = 8;		//定义一个变量,是8

function sum(){
    alert("我是sum函数,我执行了");
}

面试很容易考,就常见的面试题:

foo();
var foo;
function foo(){
    console.log(1);
}
foo = function(){
    console.log(2);
}

函数优先,

现在foo这个标识符冲突了,一个函数叫做foo,一个变量也叫作foo。预解析阶段,如果遇见标识符冲突,这个标识符给函数。

四.IIFE

IIFE就是immediately-invoked function expression,即时调用函数表达式

如果一个函数,在定义的时候,我们就想直接调用它,就是一个IIFE。

我们试图在定义函数的后面,直接写圆括号:

function fun(){
    alert("你好啊")
}();

控制台报错,这是因为函数是一个函数体,并不是表达式,只有表达式能够用()来执行。

所以就要把function fun(){}“降级”, 从函数体降级为表达式。方法有很多:

+function fun(){
	alert("你好啊")
}();

-function fun(){
	alert("你好啊")
}();

更通常更常用的:

(function fun(){
	alert("你好啊")
})();

用这种方法定义的函数,名字是无效的,其他的地方是调用这个函数

fun();

所以IIFE里面的函数,都是匿名函数:

(function(){
	alert("哈哈");
})();

上面就是一个标准的IIFE。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oBj-小飞猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值