美文网首页
第五节JavaScript函数的认识

第五节JavaScript函数的认识

作者: 心存美好 | 来源:发表于2021-10-15 17:50 被阅读0次

    一.初步了解函数

    为什么要有函数呢,我们先从函数的功能出发,来认识一下函数给我们带来的好处

    比如:

    if( 1 > 0 ){
        console.log("a");
        console.log("b");
        console.log("c");
    }
    if( 2 > 0 ){
        console.log("a");
        console.log("b");
        console.log("c");
    }
    if( 3 > 0 ){
        console.log("a");
        console.log("b");
        console.log("c");
    }
    

    当我们满足一定条件要执行一块代码,要执行一个功能,这就这个功能在很多条件满足的情况下都要执行.,我要是这么写,你会发现我代码的重复性非常高,你看这些代码都是重复的.

    还记得我们css中的属性重复吧,我们可以通过分组解决重复代码的复用问题

    那这种重复在我们js中也是不被推荐的 ,我们管这种重复叫耦合,耦合就是重复冗余的.

    那如何解决这种耦合问题呢?

    js中也存在一个这种封装的盒子, 来对代码进行复用, 这个封装的合子就是函数

    简而言之, 就是将一些复用的代码封装在一个函数中,通过函数在不同地方的使用来复用封装的代码

    直接上代码:

    function test(){
        console.log("a");
        console.log("b");
        console.log("c");
    }
    if( 1 > 0 ){
        test();
    }
    if( 2 > 0 ){
       test();
    }
    if( 3 > 0 ){
       test();
    }
    

    函数组基本的作用就是简化代码, 提高开发效率

    1. 函数的定义和调用

    函数和变量一样, 先定义(声明)在使用

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

    1.1 函数的声明

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

    1. function就是英语“功能”的意思。表示这里面定义的一个功能。
    2. function后面有一个空格,后面就是函数名字,函数的名字也是标识符,因此命名规范和变量命名是一样的。
    3. 名字后面有一对儿圆括号,里面放置参数,一会儿再介绍参数。然后就是大括号,大括号里就是封装的函数语句

    定义一个函数:

    function 函数名(){

    }

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

    1.2 函数的调用

    调用一个函数的方法非常简单,函数名后面加一个() ,() 是一个运算符,表示执行一个函数。

    function theFirstName(){
        
    }
    console.log(theFirstName);  // 弱类型的语言用于不输出内存地址,,输出指针指向的房间
    

    执行函数语句:

    函数名()

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

    函数是一些语句的集合,仔细体会, 感觉上函数就是让一些零散语句成为一个军团,集体作战。要不出动都不出动,要出动就全出动。前提得到命令(调用)才会出动(执行)。

    1. 函数的参数

    2.1 参数的了解

    上一节了解了函数的定义和使用, 但是会发现, 函数内部的语句都是相同,

    那么如果我们需要在不同的地方, 使用不同语句, 就会有问题, 那么如何解决这个问题呢?

    实际上我们可以通过“参数”这个东西,来让语句有差别。

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

    比如:

    function fun(a){
        // 参数就相当于隐式的在函数体呢var a;
        console.log("我第" + a + "次说爱你");
    }
    

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

    执行这个函数:

    fun(88);
    

    罗列在function小括号中的参数,叫做形式参数;调用时传递的数值,叫做实际参数。

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

    2.2 参数个数

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

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

    定义函数的时候,参数是什么类型的没写,不需要指定类型:

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

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

    sum("5",12);
    

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

    有了参数以后,函数就实现了真正的功能

    function sum(a,b){
        var c = a + b;
        console.log(c);
    }
    sum(1,3);    // 这就是一个求和的功能吧
    // 咱们就相当于把两个函数的规则抽象出来了
    // 这个时候是不是就像我们数学中x,y, 随便代换值
    // 这里面变量就是参数
    // 有了参数以后这里就变成了抽象规则了,而不是原来的那种聚合代码的作用
    // 原来只是为了聚合代码 不让代码重复 现在就是抽象规格的作用了
    // 有参数才变得强大,没参数发现没什么用
    

    例子:

    function sum(a,b){
        if( a > 10){
            console.log( a - b );
        }else if( a < 10){
            console.log( a + b );
        }else{
            consol.log(10);
        }
    }
    

    2.3 实参和形参个数不等(天生不定参数)

    我们还可以发现,定义的时候和调用的时候参数个数可以不一样多,不报错。

    sum(10);          //NaN 因为计算的就是10+undefined = NaN
    

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

    sum(10,20,32,23,22,2,4);   // 30
    

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

    2.4. arguments

    JS有一个非常强大的东西,就是每一个函数内部,都可以使用一个arguments这个类数组对象。

    这个arguments对象,就涵盖了所有实参。

    调用函数的时候,比如:

    fun(45,436,457,34,23,12);
    

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

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

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

    function fun(a,b){
        arguments[0] = 8;   //改变了第一个参数的值
        alert(a);       //8  ,弹出改变后的值
        // agruments[0]和a 不是同一个变量,只是函数内部有一个绳子,叫映射规则,就是我变你也的变,你变我也得变
        
        //  实参有几个,arguments就有几个,此时
        // 没有arguments[1] 
        b = 2;
        console.log(argumnts[1]);
        // 就算此时你把b改为2  也不会往arguments里面加了,
        // arguments 出生有几个就是几个
        
    }
    
    fun(45);
    

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

    那什么是重载呢?

    在Java中,同一个函数名,但是参数个数不一样,视为是两个函数。

    也就是说,Java中能够定义两个:

    function sum(a,b){
    }
    function sum(a,b,c){
    }
    

    同名的两个function,都是sum函数,但是java中是允许这么做的,因为参数个数不一样,这种现象叫做重载。

    JavaScript没有重载的概念:

    比如现在我们想设计一个sum函数,如果传进来一个参数,就得到这个数字的加1;如果是2个参数,那么返回两个数字的和。比如

    sum(10);  //1
    sum(3,4);  //7
    

    就要通过arguments.length 实际参数的个数,来进行判断:

    function sum(a,b){
        //如果实际参数的长度是1,说白了,你只传进来一个参数
        switch(arguments.length){
            case 1:
                return ++a;
                break;
            case 2:
                return a + b;
                break;
        }
    }
    

    更牛逼的,我们可以无限参数,设计一个函数sum,能够接受无限参数

    sum(3,4,6,5,8,2)   //28
    

    获取实参形参个数,判断实参和形参的个数;

    function sum(a,b,c,d){
        if()
    }
    

    用函数算累和

    function sum(){
        var result = 0;
        for(var i = 0; i < arguments.length;i++){
            result += arguments[i]
        }
        console.log(result);
    }
    sum(1,2,3,4)
    

    这是不是就是不定参的好出吧,系统内置的一些函数都是不定参的.

    1. 返回值

    3.1 函数的返回值

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

    既返回也终止

    function sum(a,b){
        return a + b;       //现在这个函数的返回值就是a+b的和
    }
    
    console.log(sum(3,8));  //sum没有输出功能,就要用console.log输出
    //sum(3,8)实际上就成为了一个表达式,需要计算
    //计算后就是11,console.log(11);
    

    函数只能有唯一的return,有if语句除外

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

    function fun(){
        console.log(1);
        console.log(2);
        return;            //返回一个空值
        console.log(3);  //这行语句不执行,因为函数已经return了
    }
    
    fun();    //1, 2
    console.log(fun()); //undefined
    
    
    function myNumber(target){
        return +target;
    }
    var num = myNumber("123");
    console.log(typeof num + " " + num);
    

    3.2 函数作为参数使用

    函数有一个return的值,那么现在这个函数,实际上就是一个表达式,换句话说这个函数就是一个值。

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

    sum(3,sum(4,5));     //12
    //输出12,实际上有两次执行了sum函数
    //先执行最内层,计算出9,然后 sum(3,9)
    //就是12
    

    程序从最内层做到最外层, sum(3,9) 12

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

    函数的意义:

    1. 在出现大量程序相同的时候,可以封装为一个function,这样只用调用一次,就能执行很多语句。

    2. 我们在调用一个函数的时候,不用关心函数内部的实现细节,甚至这个函数是你上网抄的,可以运用。所以这个东西,给我们团队开发带来了好处。

    3. 模块化编程,让复杂的逻辑变得简单。

    4. 应用函数简化编程

    我们现在做一个程序,输出2~100的所有质数。所谓的质数,就是只有1、自己两个约数,没有其他约数。

    要把一个复杂的问题,拆分为一个个小问题。

    高层的业务,就能使用底层的函数提供的API:

    约数个数函数 → 判断质数函数 → 高层业务

    //约数个数函数:能够传入一个数字,吐出来它约数的个数
    function yueshugeshu(a){
        //计算a这个数字约数的个数
        var count = 0;
        for(var i = 1 ; i <= a ; i++){
            if(a % i == 0){
                count++;
            }
        }
        return count;   //返回这个数字的约数的个数
    }
    
    
    //判断是否是质数,如果一个函数的名字取is
    //就暗示了将返回布尔值,要么是true要么是false。是通常做法,不是规定
    //接收一个参数m,返回是否是质数t或者f
    function isZhishu(m){
        if(yueshugeshu(m) == 2){
            return true;
        }else{
            return false;
        }
    }
    
    
    //寻找1~100的质数
    for(var i = 1 ; i <= 100 ; i++){
        if(isZhishu(i)){
            console.log(i);
        }
    }
    
    1. 递归

    怎么解出来不重要,这种解题方法一定要知道,这种方式叫递归

    就是频繁调用自己,只有一个好处简化代码,除此之外,没有其他好处,

    递归是不是实现的块啊,递归是最慢的,特别复杂的程序不能用递归,为什么慢,想想为什么慢

    // !n  阶乘
    function mul(){
        if( n == 1 || n == 0){
            return 1;
        }
        return n * mul(n - 1);
    }
    

    递归的规律,先执行的最后执行完

    二. 函数表达式

    定义函数除了使用function之外,还有一种方法,就是函数表达式。就是将函数声明赋值给一个变量

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

    // 命名函数表达式
    var haha = function xixi(a,b){
        return a + b;
    }
    // 这种定义方式
    console.log(haha.name);  // xixi
    

    那么JS表现非常的奇怪,在外部只能用haha()来调用,xixi()非引发错误!此时可以console.log()函数名

    console.log(haha);   // 为函数体
    console.log(xixi);   // Uncaught ReferenceError: xixi is not defined
    

    所以此时函数可以没有名字,称为“匿名函数”,为了今后能够调用它,我们把这个匿名函数,直接赋值给一个变量。

    // 匿名函数表达式  
    var haha = function(a,b){
        return a + b;
    }
    // 因为比较常用,所有以后我们讲的函数表达式就是指匿名函数表达式,
    // 如果要讲命名函数表达式会特殊强调
    

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

    console.log(haha(1,3));
    

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

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

    function haha(){
        
    }
    

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

    var haha = function(){
        
    }
    

    尽量不要用:

    var xixi = function haha(){
    }
    

    三. 函数声明的提升(预解析)

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

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

    //先调用
    fun();  //可以弹出警告框,因为函数有函数声明头提升的特性
    //然后定义
    function fun(){
        alert("我是函数,我执行了!");
    }
    

    不会引发错误,alert能够弹出。

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

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

    // ************************************
    //函数表达式不会有提升的
    fun();  //报错
    var fun = function(){
        alert("我是函数,我执行了!");
    }
    

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

    1.函数优先

    aaa();  //现在这个aaa到底是函数,还是变量5呢?
    //函数优先,遇见同名标识符,预解析阶段一定把这个标识符给函数
    
    var aaa = 5;        //定义一个变量,是5
    
    function aaa(){
        alert("我是aaa函数,我执行了");
    }
    

    面试很容易考:

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

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

    函数声明的提升,是无节操的,强制提升,即使用if语句,也会提升。

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

    例子:设计一个函数,这个函数接收三个参数,比如sum(4,7,9);返回的是前两个数字大的那个数字,与第三个数字的和。

    sum(4,2,3);   //7
    sum(2,4,3);   //7
    sum(5,4,3);   //8
    
    
    function sum(a,b,c){
        return (function(a,b){
            return a >= b ? a : b;
        })(a,b) + c;
    }
    var result=sum(3,12,9)
    console.log(result);
    

    红色部分是一个IIFE,本质上是一个表达式,表达式计算之后,就是值,什么值呢?a、b中大的那个数字。

    这样也行

    sum=function(a,b,c){
        return (function(a,b){
            return a >= b ? a : b;
        })(a,b) + c;
    }
    var result=sum(3,9,9)
    console.log(result);
    

    五. 引用类型

    我们之前说的,基本类型:number、string、boolean、undefined、null

    function fun(){
    
    }
    console.log(typeof fun);   // funtion
    

    相关文章

      网友评论

          本文标题:第五节JavaScript函数的认识

          本文链接:https://www.haomeiwen.com/subject/izbmoltx.html