【学习前端第十九课】JavaScript函数

发布时间:2024年01月20日

JavaScript函数

javascript中的函数我们可以理解成是一个封装任意多条执行语句的过程,ES中函数使用function关键字来声明,后面跟一组参数以及函数体

函数的定义

函数的定义方式很多,再目前来讲我们只看一种标准方式,语法如下

function 函数名(参数, ...){
	//函数体
}

注意点:

1、关于函数名,我们可以当成是一个标识符来看待,所以再给函数命名的时候我们需要遵循标识符的规范

2、函数的代码体(函数体)里面是可以有任意多条语句的

3、后面的大括号不能省

那么我们学习函数到底是为了什么,函数可以帮我们解决什么问题?

之前的学习中,我们在编写好js代码之后,在浏览器中运行会发现代码是被直接执行的,因为,js是一种解释性语言,解释性语言的执行特征就是,解释一句(读一句代码) ,执行一句,所以我们可以认为我们之前所写的代码都是一种立即执行的状态,那么现在我们不想让代码立即执行,而是让我们编写的代码,在程序运行之后,在某个适当的实际再执行,这个时候就可以使用到函数,将对应语句进行封装,从而让被封装到函数体内的语句变成一个等待执行的状态,然后我们再通过合适的时机调用这个函数,从而让函数体内封装的代码再次执行

function sayHello(){
	console.log("everybody hello");
}

上面我们就相当于声明了一个函数,上面的过程我们也可以叫做封装了一个方法

其他的一些声明函数的方式

var 函数名 = function(){
	//函数体
}

根据上面的写法

var sayHello = function(){
	console.log("everybody hello");
}

注意:

上面两种方式的定义看起来好像一样,实际还是有点区别的

abc();
function abc(){
	console.log("hello abc");
}

//下面的调用函数,去执行的时候会报错,def is not a function
def();
var def = function(){
	console.log("hello def");
}

通过第一种方式声明出来的函数,可以在定义函数的代码之前调用,而通过var定义的函数会报错

函数自身也是有数据类型的,它可以通过typeof去检测,检测结果是function

函数的调用

定义好的函数是不会自己执行,它需要经过调用才会被执行,函数的调用是通过函数名来完成的,语法格式如下

函数名();

在实际调用过程中会有如下情况

function test(){
    console.log("a");
}
test();  //调出该函数的函数体中所包含的代码,并执行
test  //调出来函数,但是没有执行

如果只写函数名不写后面的小括号,我们会发现,函数体内的代码并没有被执行,通过也没有报错,原有在于在调用时需要跟在函数名后面的小括号中,我们可以把这个小括号理解成是一个立即执行符,前面的函数名代码调出函数体,后面的小括号代码立即执行函数体内的代码

也就是说,我们可以调用函数的语法理解成是由两个部分组成的,由调(函数名)和用(小括号)两部分组成

函数的参数

有如下情况

var userName;
function sayHello(){
	console.log("大家好,我叫" + userName);
}

function sayGoodBye(){
    console.log(userName + "说,拜拜");
}

userName = "张三";
sayHello();   //大家好,我叫  张三
sayGoodBye();  //李四说,拜拜

userName = "李四";
sayHello();   //大家好,我叫  李四

userName = "赵五";
sayHello();   //大家好,我叫  赵五

当我们调用 sayHello() 的函数的时候,我们看到可以根据变量userName去动态改变打印出来的内容

这个时候,我们把userName的变量定义在函数的外边,因为如果定义在函数体内,那么这个变量就是一个局部变量,局部变量是无法跨函数调用,所以我们把userName定义在外边供多个函数调用

定义在外边的变量我们叫全局变量,任何时候任何地方都可以使用,但是这样也容易出现问题,就是变量冲突,在上面的例子中我们就有体现

为了解决这个冲突问题,我们就引入了参数的概念

function sayHello(userName){
	console.log("大家好,我叫" + userName);
}

//带参的函数,在声明的时候一般不给参数赋值,参数我们可以理解成就是一个变量,只不过这个变量一般情况下不在
//声明的时候赋值

sayHello("张三");
//参数一般在函数被调用的时候赋值
sayHello("李四");
sayHello("赵五");

当一个函数有了参数的引入之后,函数的作用的灵活性会有很大的提升

形参与实参

形参:形式参数,指的就是小括号里面写的参数名

实参:实际参数,调用函数的时候,括号里面的值

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

//上面的函数中,a和b就是形参,没有具体的值,也没有具体的类型

再来看下面的情况

var x = 11,y = 13;
add(x,y);  //add(11,13)

这个时候x,y是实参,因为这个是x,y是有一个实际的值存在的

通过调用函数,add的时候,实参x赋值给了a,实参y赋值给了b,函数再调用的时候,是实参赋值给形参,但是实参与形参的个数是没有必要形参一一对应的关系

所以也会有以下情况

add("hello");
add(10,20,30);

函数的重载

函数的重载指的是函数再定义的时候,它的函数名相同,而函数的参数的个数不同同时参数的类型也不同,这个同名的函数就称之为函数重载(overload)

JavaScript里面的函数没有重载,只有强类型语言才有重载

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

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

//因为js没有函数重载,所以不同通过同名函数的参数来做区分

这个时候我们看到函数名相同,但是函数的参数个数不同,我们的重载是根据参数的类型与个数来决定,但是JavaScript当中这两点都无法实现

1、javascript是弱类型语言,变量在没有赋值之前都是undefined,所以不能通过类型区分

2、JavaScript中的函数的参数,实参与形参没有必要形成一一对应的关系,这个也无法通过参数的个数去区分

所以js当中不存在重载,那么当出现同名函数的时候,会发生覆盖

函数的返回值

函数的返回值是指函数将内部某一些值返回到函数外边,它使用 return 关键字,js中每个函数都可以有返回值

首先我们通过简单的代码来理解下返回值

function abc(){
	return "hello";    
}
var x = abc();

这个时候,abc函数就有一个返回值,这个返回值是 “hello” ,然后变量x就接收了这个abc函数的返回值,所以x的值就是“hello”

function add(a,b){
	var c = a + b;
	return c;
}
var z = add(10,20);

这个时候的变量z就是接收函数add的返回值,最终结果是30

关于return关键字

return 是把函数内的值返回到函数外进行使用,同时注意,一个函数一旦碰到了 return关键字就会跳出当前函数,return后面的代码就不再执行了,如下

function abc(){
	var a = 10 + 20;
	return a;
	console.log(a);
}
var x = abc();

有时候,return关键字也可以用于跳出函数使用,后面就可以不同跟任何的值

function abc(){
	var a = 10 + 20;
	return ;
	console.log(a);
}
abc();

递归函数

如果一个函数再内部又调用了自己,那么这个函数就称为递归函数

递归函数是可以通过循环的演变来解释的,所以我们先看一个循环

//假设我们要求1-10的和
var num = 0;
for(var i = 1; i <= 10;i++){
	num += i; // num = num + i;
}
console.log(num);

上面的代码中我们要理清除几个东西

循环条件

1、初始值 i= 1

2、结束条件 i <= 10

3、自变量 i++

当前这个循环的本质

1、 i <= 10

2、num += i

3、i++

现在我们只需要让上面3各步骤去运行就可以得到结果了,不一定非要使用循环

这个时候代码就演变如下

var i = 1;
var num = 0;

function add(){
	num += i;
	i++;
	if(i <= 10){
		add();  //这行代码,代码再函数体里面又调用了自己
	}
}
add();
console.log(num);

在上面的代码里面,我们编写了一个add函数,这个函数的内部就是用了递归,它的在内部又调用了自己

通过整个分析,我们可以得到 add的函数代码的运行其实就是一个循环的执行

案例:斐波拉契数列

现在有一个数列,排列时这样的,1,1,2,3,5,8 … 问第N位应该是多少?

var a = 1;   //前二项
var b = 1;   //前一项
var c;       //当前项
for(var i = 1; i <= 9; i++){
    if(i == 1 || i == 2){
        c = 1;
    }else{
        c = a + b; //相当于完全了当前项的计算
        a = b;     //前一项值变成前二项
        b = c;     //当前项的值变成前一项
    }
}
console.log(c);

如果通过递归的方式来完成:

function abc(n){
if(n == 1 || n == 2){
    return 1;  //代表第一项和第二项的时候
}else{
    return abc(n - 1) + abc(n - 2);
    //  abc(5)                    + abc(4)
    //  abc(4)           + abc(3)          + abc(3) +           abc(2)
    //  abc(3) + abc(2)  + abc(2) + abc(1) + abc(2) + abc(1)
    //  abc(2) + abc(1) + abc(2)  + abc(2) + abc(1) + abc(2) + abc(1) + abc(2)
	} 
}
var x = abc(6);

变量的作用域

我们之前学习的时候是通过var来定义变量的,通过var定义的变量是没有所谓的“块级作用域”

var a = 123; //全局变量
if(true){
	console.log(a);
}
//-------------------------------------
{
  var a = 123;  //全局变量
}
console.log(a);
//--------------------------------------
for(var i = 1; i <= 10;i++){
	var c = "haha";
}
console.log(c);

这几个变量在这里全都是全局变量,这里的大括号没有形成作用域,它与其他的编程语言不一样的,但是这样注意一点,function的大括号会形成作用域

function abc(){
	var a = 1;  //这是一个局部变量,只能在大括号内调用,出了大括号就不能再使用了
}
console.log(a);  //这里会报错,因为a是一个局部变量
文章来源:https://blog.csdn.net/weixin_65729202/article/details/135663400
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。