个人主页:


3,arguments

当我们不确定有多少个参数传递的时候,我们就可以使用arguments来获取。

在JavaScript中,arguments这个是啥?arguments实际上是当前函数的一个内置函数。

所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有参数。

arguments展示形式是一个伪数组,因此可以像数组一样进行遍历。

那数组与伪数组有啥区别呢?伪数组具有以下特性:

  • 具有数组的length属性
  • 按索引方式进行存储数据
  • 不具有数组的push,pop等方法

为了更好地理解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>

示例结果:


1.4,函数返回值

当函数完成了函数代码块的基本功能后,需要通过函数的返回值来将函数的处理结果返回。

函数返回值是通过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>

示例结果:


2,函数进阶

2.1,函数表达式

函数表达式是将声明的函数赋值给一个变量,通过变量完成函数的调用和参数的传递。

为了更好理解函数表达式,示例如下:

<script>    var sum = function(num1,num2){   //函数表达式        return num1 + num2;    };     console.log(sum(13,14));         //调用函数</script>

示例结果:

知识点:

  • 函数表达式与函数声明的定义方式几乎相同,不同的是函数表达式的定义必须在函数调用之前,而函数声明的方式则不限制声明与调用顺序。

2.2,回调函数

回调函数指的是一个函数A作为参数传递给一个函数B,然后在函数B的函数体内调用函数A,此时函数A被称为回调函数。

其中,匿名函数常用作函数的参数传递,从而实现回调函数。

为了更好理解何为回调函数及使用,示例如下:

    function fn1(num1,num2,fn){        return fn(num1,num2);    }    console.log(fn1(45,55,function(a,b){        return a + b;    }));

示例结果:

知识点

  • 在函数中设置了回调函数后,可以根据调用时传递的不同参数(相加的函数,相乘的函数等),在函数体中特定的位置实现不同的功能,相当于在函数体内根据用户的需求来完成了不同功能的定制。

2.3,递归函数

函数的递归指的是一个函数在其函数体内调用自身的过程。需要特别注意的是 ,函数递归只可在特定的情况下使用。

为了更好地理解何为递归函数及使用,示例如下:

<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。

注意:递归调用虽然在遍历维数不固定的多维数组时非常适合,但它占用的内存和资源比较多,同时难以实现和维护,因此在开发中需谨慎使用。


3,作用域

3.1,作用域分类

一般来说,一段代码中所用到的变量名或函数名并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

作用域的目的就是为了有效减少命名冲突的情况。变量需要先声明后使用,但不意味着声明变量后就可以在任意位置使用该变量。

例如,在函数声明一个age变量,在函数外进行访问,就会出现age变量未定义的错误。

<script>    function fun(){        var age = 19;    }    console.log(age);</script>

示例结果:

从上述代码可以知道,变量需要在它的作用域范围内才可以被使用,这个作用域被称为变量的作用域。

JavaScript根据作用域使用范围的不同,将其划分为全局作用域,函数作用域和块级作用域(ES6提供的)。

  • 全局作用域是整个script标签 或者 一个单独的JavaScript文件。
  • 局部作用域也称函数作用域,在函数内部就是函数作用域,这个代码名字只能在函数内部起效果和作用。

为了更好理解上述语法,示例如下:

<script>    //全局作用域    var num = 20;            //全局变量    function fun(){        //局部作用域        var num = 10;        //局部变量        console.log(num);    //输出局部变量值:10    }    fun();    console.log(num);        //输出全局变量值:20</script>

3.2,变量分类

在JavaScript中,对不同的作用域内声明的变量进行划分,可划分为全局变量,局部变量,块级变量三类。

  • 全局变量:不在任何函数内声明的变量(显式定义)或在函数内省略var声明的变量隐式定义)都称为全局变量,它在同一个页面文件中的所有脚本内都可以使用。
  • 局部变量:在函数体内利用var关键字定义的变量称为局部变量,它仅在该函数体内有效。
  • 块级变量:ES6提供的let关键字声明的变量称为块级变量,仅在“0”中间有效,如if、for或while语句等。

知识点:

  • 当全局变量名和局部变量名相同时,两者的使用互不影响。
  • 局部变量只能在函数内部使用,函数的形参也属于局部变量。
  • 函数中的变量如果省略var关键字,它会自动向上级作用域查找变量,一直找到全局作用域为止。
    function fn(){        num = 10;    }    fn();    console.log(num);


  • 在全局作用域下,添加或者省略var关键字都可以声明全局变量。而在函数中,添加var关键字声明的变量是局部变量,省略var关键字时,如果变量在当前作用域不存在,会自动向上级作用域查找变量。

  • 从执行效率来说,全局变量在浏览器关闭页面的时候才会销毁,比较占用内存资源;而局部变量在函数执行完成后就会被销毁,比较节约内存资源。


3.3,作用域链

当在一个函数内部声明另外一个函数时,就会出现函数嵌套的效果。当函数嵌套时,内层函数只能在外部函数作用域内执行,在内层函数执行过程中,若需要引入某个变量,首先会在当前作用域中寻找,若未找到,则继续向上一层级的作用域中寻找,直到全局作用域。

简而言之,作用域链是指内部函数访问外部函数的变量,采取的是链式查找的方式来决定那个值。

为了更好理解上述作用域链的语法,示例如下:

<script>    var num = 10;    function fn(){              //外部函数        var num = 20;        function fun(){         //内部函数            console.log(num);   //输出num值:20          }                       //口诀:就近原则        fun();    }    fn();       </script>

示例结果:


4,闭包函数

在JavaScript中,内嵌函数可以访问定义在外层函数中的所有的变量和函数,并包括其外层函数能访问的所有变量和函数。

但是在函数外部则不能访问函数的内部变量和嵌套函数,此时可通过使用闭包来实现。

**那闭包是啥东东呢?**闭包指的就是有权访问另一函数作用域内变量(局部变量)的函数。

那闭包有啥用呢? 闭包的用途可归纳为以下两种:

  1. 可以在函数外部读取函数内部的变量。
  2. 可以让变量的值始终在内存中。

知识点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>

示例结果:


5,预解析

JavaScript代码由浏览器中的JavaScript解析器来执行的,JavaScript解析器在运行JavaScript代码时会进行预解析。

**那该如何理解预解析呢?**预解析就是提前将代码中的var变量声明和function函数声明进行解析,然后再去执行其它的代码。

JavaScript引擎运行JavaScript分为两步:预解析和代码执行。

预解析分为变量预解析(变量提升)和函数预解析(函数提升)两类。

  1. 变量提升就是将所有的变量声明提升到当前作用域的最前面,但不提升赋值操作。
  2. 函数提升就是将所有的函数声明提升到当前作用域的最前面,但不调用函数。

为了更好理解预解析的使用,示例如下:

预解析示例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中函数的相关内容有了全新地认识和理解吧,如果有什么其他的问题无法自己解决,可以在评论区留言哦!

最后,如果你觉得这篇文章写的还不错的话或者有所收获的话,麻烦小伙伴们动动你们的小手,给个三连呗(点赞,评论✍,收藏),多多支持一下!各位的支持是我最大的动力,后期不断更新优质的内容来帮助大家,一起进步。那我们下期见!