最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript网页编程之函数

    正文概述 掘金(Devil)   2020-12-21   455

    函数

    函数表达式

    函数表达式是函数定义的另外一种方式。

    • 定义方法:将函数的定义、匿名函数赋值给一个变量。
    • 调用函数表达式,方法是给变量名加()执行,不能使用函数名加()执行。
      // 函数的定义
      var foo = function fun (){
          console.log(1);
      }
      // 函数的调用
      fun();  // 控制台输出未定义错误
      foo();  // 成功调用该函数,由此可以看出使用匿名函数即可
    

    函数的数据类型

    • 函数是一种单独的数据类型Function(包含在object中)
    • 由于函数是一种数据类型,可以参与其他程序
      • 可把函数作为另一个函数的参数,在另一个函数中调用。
        // 定时器
        // 函数是一种数据类型,可以当成其他函数的参数
        setInterval(function(){
            console.log(1);
        },1000);
      
      • 可把函数作为返回值从函数内部返回
        function fn(b){
            var a = 10;
            return function(){
                alert(a + b);
            }
        }
      

    arguments对象

    所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有的实参。arguments是一个伪数组,因此可以进行遍历。

    • 函数的实参个数和形参个数可以不一致,所有的实参都会存储在函数内部的arguments类数组对象中。
      // 定义一个函数
      function sum(a,b){
          return a + b;
      }
    
      // 调用函数  函数的实参个数和形参个数可以不一致
      console.log(sum(1));  // NaN 因为第二个形式参数没有赋值,那么默认值为undefined,undefined + 1 = NaN;
      console.log(sum(1,2)); // 3
      console.log(sum(1,2,3,4)); // 3
    
      // 函数内部有一个arguments对象,会接收所有的实参
      // arguments的存取方式和数组arr类似,通过下标来完成
      function fun() {
          console.log(arguments); // Arguments(6)[1,2,3,4,5,6]
          console.log(arguments.length); // 6
      }
      // 调用定义的函数
      fun(1,2,3,4,5,6); 
    
    • 案例:定义一个求和函数,如果传入 1 个参数,返回它自己,如果传入两个参数,返回他们的和,如果传入三个参数,先比较前两个的大小,大的与第三个参数求和返回,如果传入 4 个及以上,输出错误提示。
      function sum(a,b,c){
        switch(arguments.length){
            case 1:
                return a;
            case 2:
                return a + b;
            case 3:
                return a > b ? a + c : b + c;
            default:
                // 提示用户,实参个数传递错误
                //模拟控制台报错
                throw new Error("参数个数不能超过3个");
        }
    }
    console.log(sum(1));  // 1
    console.log(sum(1,2)); // 3
    console.log(sum(1,2,3)); // 5
    console.log(sum(1,2,3,4)); // 报错
    

    函数递归

    • 函数内部可以通过函数名调用函数自身的方式。
    • 递归的次数太多容易出现错误:超出计算机的计算最大能力。
    • 案例:输出斐波那契数列的某一项的值。斐波那契数列:后面的一项数据是前两项数据之和。1,1,2,3,5,8,13,21,34,55……
      function fbo(a) {
        if(a == 1 || a == 2){
            return 1;
        }else {
            return fbo(a - 1) + fbo(a - 2);
        }
    }
      console.log(fbo(1));
      console.log(fbo(2));
      console.log(fbo(3));
      console.log(fbo(4));
    

    作用域

    变量可以起作用的范围

    • 函数作用域:如果变量定义在一个函数内部,只能在函数内部被访问到,在函数外部不能使用这个变量,函数就是变量定义的作用域。
    • 块级作用域:任何一对花括号{}中的结构体都属于一个块,在这之中定义的所有变量在代码块外都是不可见的。
    • es5之前没有块级作用域的概念,只有函数作用域,现阶段可以认为JavaScript没有块级作用域。

    变量根据作用域不同划分为两类

    • 全局变量:从广义上来说,也是一种局部变量,定义在全局的变量,作用域范围是全局,在整个 js 程序任意位置都能够被访问到。
    • 局部变量:在函数被调用,内存会开辟一部分空间去执行函数并声明其中的局部变量,当函数执行完,这块内存区域就会立即被释放。(函数的形式参数也属于局部变量)
    • 两者的区别:变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁

    参数和函数的作用域

    • 函数的形式参数也属于局部变量。,函数的参数也是属于函数自己内部的局部变量,只能在函数内部被使用,在函数外面没有定义
    • 在函数中定义的函数,只能在定义函数的函数的范围内进行调用,到了全局会失效。
      // 不正确的写法
      function outer(a) {
        a = 1;
        console.log(a);
        function inner() {
          console.log("我是inner");
        }
        // 正确写法:在这里进行调用 inner();
      }
      // 调用函数
      outer(1);
      inner(); // 控制台会报错,undefined
    

    作用域链和遮蔽效应

    • 只要是代码,就至少有一个作用域,即:全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。

    • 作用域链:将这样的所有的作用域列出来,可以有一个结构 -> 函数内指向函数外的链式结构

      • 案例:
          // f1函数:0级链
          function f1() {
        
            // f1函数中的num变量:1级链
            var num = 123;
        
            // f1函数中的f2函数:1级链
            function f2() {
              // f2函数中的num变量:2级链
              console.log(num);
            }
                
            f2();
          }
        
          // num变量:0级链
          var num = 456;
          f1();
        
        案例配图:JavaScript网页编程之函数
    • 遮蔽效应

      • 程序在遇到一个变量时,使用时作用域查找顺序,不同层次的函数内都有可能定义相同名字的变量,一个变量在使用时,会优先从自己所在层作用域查找变量,如果当前层没有变量定义会按照顺序从本层往外依次查找,直到找到第一个变量定义(如果一直没有找到,那么就会在控制台报错 is no defined.)。整个过程中会发生内层变量遮蔽外层变量的效果,叫做“遮蔽效应”。
      • 案例:
        /*
        找不到的情况:
          当执行f2()函数中的console.log(num);时,
          会先查找f2()函数(2级链)中是否有num,有就输出;
          假设不存在的话,就会往上一层f1()函数(1级链)中去找,有就输出num;
          假设还是不存在的话,就还要往上一层找,有就输出num(当前已是最外层:0级链);
          假设还是不存在的话,程序就会在控制台报错。
        
        遮蔽效应:最近的会遮盖较远的
        */
            // num变量:0级链
            var num = 456;
        
            // f1函数:0级链
            function f1() {
        
              // f1函数中的num变量:1级链
              var num = 123;
        
              // f1函数中的f2函数:1级链
              function f2() {
                var num = 78;
        
                // f2函数中的num变量:2级链
                console.log(num);
              }
                  
              f2();
            }
        
            f1();
        

    不写var关键字的影响

    • 在函数内部想要定义新的变量,如果不加关键字 var,相当于定义的全局变量。如果全局也有相同的标识符,会被函数内部的变量影响,局部变量污染全局变量。
        // 全局变量
        var a = 1;
        function fun() {
          a = 2;
          console.log(a); // 2
        }
        // 局部变量污染全局变量。
        console.log(a); // 2  
      

    预解析

    • javascript代码的执行是由浏览器中的javascript解析器来执行的。javascript解析器执行javascript代码的时候,分为两个过程:预解析过程和代码执行过程。
    • 预解析过程:
        1. 变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
        1. 函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
        1. 先提升var,再提升function
    • javascript的执行过程:在预解析之后,根据新的代码顺序,从上往下按照既定规律执行js代码。

    变量声明提升

    • 提升过程中,只提升声明过程,不提升变量赋值,相当于变量定义未赋值,变量内存储undefined 值
    • 因此,在js中会出现一种现象,在前面调用后定义的变量,不会报错,只会使用undefined 值

    函数声明提升

    • 在预解析之后的代码执行过程中,函数定义过程已经在最开始就会执行,一旦函数定义成功,后续就可以直接调用函数。
    • 因此,在 js 中会出现一种现象,在前面调用后定义的函数,不会报错,而且能正常执行函数内部的代码

    提升顺序

    预解析过程中,先提升 var 变量声明,再提升function 函数声明。

    • 假设出现变量名和函数名相同

      • 那么后提升的函数名标识符会覆盖先提升的变量名
      • 在后续的代码中出现调用标识符时,内部是函数的定义过程,而不是undefined.
        // 模拟预解析过程
        /* 
          提前变量声明,执行后fun = undefined
          var fun;
      
          提前函数声明,执行后fun中覆盖前面的undefined,变成fun函数的定义过程
          function fun(a) {
            a = 1;
            return a;
        }
        */
        /* 执行下面这句输出语句,得到的结果:  
          ƒ fun(a) {
            a = 1;
            return a;
        }
        显然可以看出来undefined已经被覆盖
        */
        console.log(fun);
          
        // 在函数定义过程前面调用函数,也不会报错
        var b = fun();
        console.log(b); // 1
        // 函数定义
        function fun() {
            return 1;
        }
          
        // 给fun赋值,fun变成Numner类型
        var fun = 1;
        console.log(fun); // 1
      
        /* 再次调用fun函数的时候,就报错了
           Uncaught TypeError: fun is not a function
           类型错误:因为前面给fun赋值为一个数字类型了,其已经不是函数,无法执行调用。
        */
        var c = fun();
        console.log(c); // Uncaught TypeError: fun is not a function
      
      • 如果调用标识符的过程在源代码函数和变量定义后面,相当于函数名覆盖了一次变量名,结果在执行到变量赋值时,又被新值覆盖了函数的值,那么在后面再次调用标识符,用的就是变量存的新值。
    • 建议:不要书写相同的标识符给变量名或函数名,避免出现覆盖。

    函数表达式的提升

    • 在预解析过程中,函数表达式进行的是变量声明提升,而不是函数声明提升。提升后变量内部存的是一个 undefined。在前面进行函数方法调用,数据类型会提示错误。
       /* 模拟预解析
         var foo;  此时内部存储:undefined
         因此使用函数表达式方法,不能再函数定义过程之前调用函数,会报错
       */
       foo();  // Uncaught ReferenceError: fun is not defined
    
       var foo = function (){
           console.log(5);
       }
    
    • 建议:定义函数时,最好使用 function 关键字定义方式,这样函数声明提升可以永远生效。

    函数声明提升的应用

    • 函数声明提升可以用于调整代码的顺序,将大段的定义过程放到代码最后,但是不影响代码执行效果。

    IIFE自调用函数

    • IIFE:immediately-invoked function expression,叫做即时调用的函数表达式,也叫做自

    调用函数,表示函数在定义时就立即调用

    • 函数调用方式:函数名或函数表达式的变量名后面加 () 运算符。
    • 函数名定义的形式不能实现立即执行自调用,函数使用函数表达式形式可以实现立即执行,原因是因为函数表达式定义过程中,将一个函数矮化成了一个表达式,后面加()运算符就可以立即执行。
      // 函数名+() 不能实现立即执行自调用
      function fun (){
          console.log(1);
      }();
    
      // 函数表达式形式可以实现立即执行
      var foo = function (){
          console.log("halou");
      }();  // 没有调用语句,直接输出:halou
    
    
    • 启发:如果想实现 IIFE,可以想办法将函数矮化成表达式。

    函数矮化成表达式

    函数矮化成表达式,就可以实现自调用。

    • 函数矮化成表达式的方法,可以让函数参与一些运算,也就是说给函数前面加一些运算符。(四个)
      • 数学运算符:+ - ()
      • 逻辑运算符:!非运算
        + function fun (){
            console.log(1); // 1
        }();
        - function fun (){
            console.log(1); // 1
        }();
        (function fun (){
            console.log(1); // 1
        })();
        ! function fun (){
            console.log(1); // 1
        }();
      
    • IIFE 结构可以关住函数的作用域,在结构外面是不能调用函数的。
    • IIFE 最常用的是 () 运算符,而且函数可以不写函数名,使用匿名函数。
    
      (function fun (a){  // 形参会接收到实参传递的值
            console.log(a);  // Hello
        })("Hello!");  //因为外部无法调用该函数,也无法传实参,因此实参写在这个小括号里面 
    

    起源地下载网 » JavaScript网页编程之函数

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元