个人主页:「小杨」的csdn博客
系列专栏:【JavaScript速成之路】
希望大家多多支持一起进步呀!
前言:小杨在上一篇带着大家一起学习了JavaScript中的数组,想必大家对JavaScript的数组知识已经有所了解了,那么今天我们将继续带着大家学习一下JavaScript中的函数的相关知识,希望大家收获多多!
函数就是封装了一段可以被重复执行调用的代码块。
函数引入的目的就是为了解决代码的重复问题,让代码重复使用。
函数使用可分为两步,即声明函数和调用函数两部分。
1,声明函数语法:
function 函数名(参数列表){
//函数体
}
知识点:
2,调用函数语法:
函数名();
知识点:
3,函数封装
函数具有封装代码的效果,也就是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。
封装思想类似于将计算机内部的主板,CPU中央处理器,内存等硬件全部安装到机箱里,对外只提供一些像电源接口,显示接口,USB接口这样简单的接口给用户使用。
在函数内部的代码中,当某些值不能确定时,可以通过函数的参数从外部接收,一个函数可以通过传入不同的参数来完成不同的操作。
1,参数分类
函数参数分为形参和实参两种。
形参是指在声明函数时,函数名后面的小括号里添加的一些参数。
实参是指在调用函数时,传递给函数的对应形参的一些参数。
为了更加直观的辨别形参和实参,示例如下:
function 函数名(形参1,形参2,形参3....){ //函数声明的小括号里面的参数
//函数体代码
}
函数名(实参1,实参2,实参3....); //函数调用的小括号里面的参数
知识点:
函数的形参是形式上的参数,因为当函数声明时,这个函数还没有被调用,这些形参具体传入值是不确定的。
函数的实参则是实际上的参数,因为在函数调用时,这些形参的值就会被确定下来,传递给与之对应的形参。
2,参数数量
JavaScript函数参数的使用比较灵活,允许函数的形参和实参个数不同。
为了更好地理解上述语法,示例如下:
<script>
function getNums(num1,num2){
console.log(num1,num2);
}
getNums(1); //实参个数少于形参个数
getNums(1,2); //实参个数等于形参个数
getNums(1,2,3); //实参个数多于形参个数
</script>
示例结果:
3,arguments
当我们不确定有多少个参数传递的时候,我们就可以使用arguments来获取。
在JavaScript中,arguments这个是啥?arguments实际上是当前函数的一个内置函数。
所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有参数。
arguments展示形式是一个伪数组,因此可以像数组一样进行遍历。
那数组与伪数组有啥区别呢?伪数组具有以下特性:
为了更好地理解arguments的使用,示例如下:
<script>
function fn(){
console.log(arguments); //arguments里存储所有传递过来的参数
console.log(arguments.length); //arguments具有数组的length属性
console.log(arguments[0]); //arguments按索引方式进行存储数据
}
fn(1,2,3,4);
</script>
示例结果:
当函数完成了函数代码块的基本功能后,需要通过函数的返回值来将函数的处理结果返回。
函数返回值是通过return语句来实现的,语法格式:
function 函数名(){
return 要返回的值;
}
函数返回值使用有以下两种方式:
1,通过变量接收返回值
var result = 函数名();
console.log(result);
2,直接输出函数返回值
console.log(函数名());
知识点:若函数没有使用return返回一个值,则函数调用后获取的返回结果为undefined。
为了更好地理解函数返回值的语法,示例如下:
<script>
function getResult(){
return 121;
}
var result = getResult();
console.log(result);
console.log(getResult());
</script>
示例结果:
函数表达式是将声明的函数赋值给一个变量,通过变量完成函数的调用和参数的传递。
为了更好理解函数表达式,示例如下:
<script>
var sum = function(num1,num2){ //函数表达式
return num1 + num2;
};
console.log(sum(13,14)); //调用函数
</script>
示例结果:
知识点:
回调函数指的是一个函数A作为参数传递给一个函数B,然后在函数B的函数体内调用函数A,此时函数A被称为回调函数。
其中,匿名函数常用作函数的参数传递,从而实现回调函数。
为了更好理解何为回调函数及使用,示例如下:
示例结果:
知识点:
函数的递归指的是一个函数在其函数体内调用自身的过程。需要特别注意的是 ,函数递归只可在特定的情况下使用。
为了更好地理解何为递归函数及使用,示例如下:
<script>
function fun(n){
if(n == 1){
return 1;
}
return n * fun(n - 1);
}
var ret = fun(5);
console.log(ret);
</script>
示例结果:
示例说明:上述代码定义了一个递归函数fun()用于实现n的阶乘计算,当n不等于1时,递归当前变量n乘以fun(n-1),直到n等于1时,返回1。
注意:递归调用虽然在遍历维数不固定的多维数组时非常适合,但它占用的内存和资源比较多,同时难以实现和维护,因此在开发中需谨慎使用。
一般来说,一段代码中所用到的变量名或函数名并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的目的就是为了有效减少命名冲突的情况。变量需要先声明后使用,但不意味着声明变量后就可以在任意位置使用该变量。
例如,在函数声明一个age变量,在函数外进行访问,就会出现age变量未定义的错误。
<script>
function fun(){
var age = 19;
}
console.log(age);
</script>
示例结果:
从上述代码可以知道,变量需要在它的作用域范围内才可以被使用,这个作用域被称为变量的作用域。
JavaScript根据作用域使用范围的不同,将其划分为全局作用域,函数作用域和块级作用域(ES6提供的)。
为了更好理解上述语法,示例如下:
<script>
//全局作用域
var num = 20; //全局变量
function fun(){
//局部作用域
var num = 10; //局部变量
console.log(num); //输出局部变量值:10
}
fun();
console.log(num); //输出全局变量值:20
</script>
在JavaScript中,对不同的作用域内声明的变量进行划分,可划分为全局变量,局部变量,块级变量三类。
知识点:
在全局作用域下,添加或者省略var关键字都可以声明全局变量。而在函数中,添加var关键字声明的变量是局部变量,省略var关键字时,如果变量在当前作用域不存在,会自动向上级作用域查找变量。
从执行效率来说,全局变量在浏览器关闭页面的时候才会销毁,比较占用内存资源;而局部变量在函数执行完成后就会被销毁,比较节约内存资源。
当在一个函数内部声明另外一个函数时,就会出现函数嵌套的效果。当函数嵌套时,内层函数只能在外部函数作用域内执行,在内层函数执行过程中,若需要引入某个变量,首先会在当前作用域中寻找,若未找到,则继续向上一层级的作用域中寻找,直到全局作用域。
简而言之,作用域链是指内部函数访问外部函数的变量,采取的是链式查找的方式来决定那个值。
为了更好理解上述作用域链的语法,示例如下:
<script>
var num = 10;
function fn(){ //外部函数
var num = 20;
function fun(){ //内部函数
console.log(num); //输出num值:20
} //口诀:就近原则
fun();
}
fn();
</script>
示例结果:
在JavaScript中,内嵌函数可以访问定义在外层函数中的所有的变量和函数,并包括其外层函数能访问的所有变量和函数。
但是在函数外部则不能访问函数的内部变量和嵌套函数,此时可通过使用闭包来实现。
**那闭包是啥东东呢?**闭包指的就是有权访问另一函数作用域内变量(局部变量)的函数。
那闭包有啥用呢? 闭包的用途可归纳为以下两种:
知识点1:由于闭包会使得函数中的变量一直被保存在内存中,内存消耗很大,所以滥用闭包可能会降低程序的处理速度,造成内存消耗等问题
知识点2:常见的闭包创建的方式就是在一个函数内部创建另外一个函数,通过另外一个函数访问这个函数的局部变量。
为了更好地理解该知识点,示例如下:
<script>
function fun(){
var num = 0;
var a = function(){
return ++num;
};
return a;
}
//保存fun返回的函数,此时ret就是一个闭包
var ret = fun();
//访问测试
console.log(ret());
console.log(ret());
console.log(ret());
console.log(ret());
console.log(ret());
</script>
示例结果:
JavaScript代码由浏览器中的JavaScript解析器来执行的,JavaScript解析器在运行JavaScript代码时会进行预解析。
**那该如何理解预解析呢?**预解析就是提前将代码中的var变量声明和function函数声明进行解析,然后再去执行其它的代码。
JavaScript引擎运行JavaScript分为两步:预解析和代码执行。
预解析分为变量预解析(变量提升)和函数预解析(函数提升)两类。
为了更好理解预解析的使用,示例如下:
预解析示例1:
<script>
function fn(){
var num2 = 456;
console.log(num1);
console.log(num2);
var num1 = 123;
}
fn();
</script>
上述代码经过预解析的处理后:
<script>
function fn(){
var num2;
var num1;
num2 = 456;
console.log(num1);
console.log(num2);
num1 = 123;
}
fn();
</script>
预解析示例1结果:
预解析示例2:
<script>
fn1();
console.log(c);
console.log(b);
console.log(a);
function fn1(){
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
</script>
上述代码经过预解析的处理后:
<script>
function fn1(){
var a;
a = 9;b = 9;c = 9; //b和c为全局变量,a为局部变量
console.log(a);
console.log(b);
console.log(c);
}
fn1();
console.log(c);
console.log(b);
console.log(a);
</script>
预解析示例2结果:
这就是本期博客的全部内容啦,想必大家已经对JavaScript中函数的相关内容有了全新地认识和理解吧,如果有什么其他的问题无法自己解决,可以在评论区留言哦!
最后,如果你觉得这篇文章写的还不错的话或者有所收获的话,麻烦小伙伴们动动你们的小手,给个三连呗(点赞,评论✍,收藏),多多支持一下!各位的支持是我最大的动力,后期不断更新优质的内容来帮助大家,一起进步。那我们下期见!