JavaScript函数

153 阅读6分钟

1. 函数定义

函数的两种定义方式
  1. 声明式定义函数
    - 语法:  function 函数名(){ 函数代码 }
      + function 关键字和 函数名 之间的空格不能省略
      + 函数名后面的小括号不能省略: 小括号中是写 形参
      
      // 声明式定义函数
      function fn() {
        console.log('这是fn函数')
      }
      
  2. 赋值式定义函数----和之前讲的定义变量并赋值是一样
    - 语法: var 变量名 = function (){ 函数代码 }
      + 赋值给变量的是一个没有名字的函数(匿名函数)

      // 赋值式定义函数
      var ff = function () {
        console.log('赋值式定义函数')
      }
    console.log(ff)    // 打印了 ff 这个变量内部存储的值
    console.log(ff())  // 打印了 ff 这个函数的执行结果, 一般默认是 undefined
    
     声明式与赋值式的区别
     * 
     *      1. 写法不同
     *      2. 调用上略有不同
     *              声明式定义的函数, 可以在 函数定义前 去调用  (先不考虑原理)
     *              赋值式定义函数, 不能再函数定义前 去调用
     *          
     赋值式定义函数不能在函数定义前调用的原因
     *          赋值式定义, 其实就是声明一个变量, 然后给他赋值为一个函数
     *         在JS中, 如果在定义变量之前 使用变量的话, 那么变量的值为 undefined
     * 
     *      函数的执行结果, 一般默认都是 undefined,除非手动更改

2. 函数调用

  调用语法: 函数名()  /  变量名()
  返回值:函数的执行结果, 一般默认都是 undefined
  
  声明式定义的函数 
  fn();
  function fn() {
    console.log( 'fn' )
  }
  fn();

  赋值式定义的函数
  ff(); // 报错  ff is not a function
  var ff = function () {
    console.log('ff')
  }
  ff();
  注意: 在js中代码执行报错,会终止主程序的执行(报错之后的代码不会执行)
  
  两种定义函数的方式 ,在函数调用时候的区别:
  1)声明式定义的函数,可以在定义之前或者定义之后调用该函数
  2)赋值式定义的函数,只能在定义之后调用该函数

函数的两个阶段(定义、调用)

1. 定义
           => 在堆内存开一个空间
           => 将函数的函数体内的代码 保存到堆内存中
           => 将堆内存的地址保存在变量名(函数名), 最后将这个变量名存储在栈内存中
   
2. 调用
           => 根据变量名(函数名)中的地址, 找到对应的函数
           => 然后再调用栈中开一个新的空间(函数的执行空间)
           => 在执行空间中 对函数的形参进行赋值
           => 在执行空间中 进行变量的预解析
           => 在执行空间中 执行函数的代码
           => 销毁当前函数的执行空间
    案例1 
           var num = 666;
           function ff() {
             console.log( num )
           }

           var fn = function () {
             console.log( num )
           }
           ff()
           fn()
       
        函数定义阶段:
      1. 在内存中开辟一个空间(创建了一个盒子)
      2. 将函数中的代码一模一样的放到这个空间中,此时不会解析函数中的变量num
        - (相当于将函数中的代码,当做字符串一样放到开辟的空间中)
      3. 将开辟的空间的 地址赋值给函数名ff/变量名fn

    函数调用阶段:
      1. 先根据函函数名ff/变量名fn中存储的地址,找到 函数代码的存储空间
      2. 将函数存储空间中的代码拿出来执行,此时才会解析函数中的变量num,num=666

     案例2
           function fn() {
            var num = 200;
            console.log( num )
          }
          fn()


        fn函数调用
          根据fn中存储的地址,找到函数的存储空间 `0x001` 
          在运行内存中开辟一个函数的 执行空间 `0x00f``0x001` 中的代码拿过来在 执行空间 `0x00f` 中执行
            将100赋值给变量num,控制台输出num的值100,函数代码执行结束
          函数的执行空间 `x000f` 销毁

        问题:
          在函数执行空间中定义的变量num(或者函数的形参也是在该执行空间的变量)
          随着执行空间的销毁 也 销毁了
          如果在函数代码执行结束后,想要继续保存变量num ,如何实现?
            如果函数的执行空间不销毁,则函数内的变量也不会销毁

3. 函数的参数

函数的参数分为两种

  1. 形参
    - 形参,在函数定义的时候 写到小括号中的变量----形式参数
      + 形参相当于在函数内部创建了一个变量, 变量实际的值由  "实参" 传递
      + 如果有多个形参,使用逗号分隔
      
  2. 实参
    - 实参,在函数调用的时候,写在小括号中的具体的数据,如果有多个也是用逗号分隔
      + 实参 在函数调用的时候,将自身的值, 按照一一对应的关系, 传递给 形参
      

函数形参赋值的注意事项:

    1. 形参的数量如果大于实参
      - 那么会将 实参按照顺序一一传递给 对应的形参
      -多出来的形参, 相当于变量只定义没赋值, 所以他们的值  是 undefined
      
       function fn(n, m, x, y) { // 形参n 在函数内使用的变量
         console.log(n, m, x, y)
       }
       fn(100, 200); // 100 200 undefined undefined
                 
    2. 实参的数量如果大于形参
      -实参按照顺序 一一传递给对应的形参
      - 多出来的实参,在函数内部不能通过 形参 得到这个实参的值
      fn(10,20,30,40,50) // 10 20 30 40
      
    3. 函数内的arguments关键字,只能在函数内使用
      - arguments接收了 所有 函数调用时候传递 的实参

      function ff(n1,n2) {
        //1. arguments 会接收所有函数调用传递的实参
        console.log( arguments )
        //2. 在函数内部,可以通过 arguments[下标] 获取对应的实参
        console.log( arguments[0] )
        console.log( arguments[1] )
        console.log( arguments[2] )
        //3. 可以通过arguments.length 获取实参的个数
        console.log( arguments.length )

      }
      ff(10,20,30,40,50,60);

函数参数的默认值

     函数参数的默认值      
     函数再创建形参的时候, 默认给一个值, 将来在调用函数的时候, 
     如果没有传递,那么这个形参的值也不会是 undefined 而是给的默认值
     如果传递了对应的值, 那么形参的值是实参传递进来的值, 否则按照默认值来运行
    
    function fn(a = 100, b = '我是形参b', c) {
        console.log(a, b, c)
    }
    fn(1) // 1 '我是形参b' undefined

4. 函数的返回值

函数内的关键字return
  - 作用
    1. return 会终止函数内代码的执行(return关键字,下一行的代码不会执行了)
           function ff() {
           console.log( 1 )
           console.log( 2 )
           return;  // 函数内的代码执行到此处的时候,后面的代码就不会执行了
           console.log( 3 )
           console.log( 4 )
         }
         ff();
         
    2. return 可以给函数创造一个返回值        
      1) return 关键字后面跟的是什么内容,函数调用返回的结果就是什么
             function fn(a, b) {
                var sum = a + b
                 return sum
             }
            var num = fn(50, 50)
            console.log('num 的值: ', num)  // num 的值: 100
    
      2) return 关键字后如果什么都没写,则函数的返回值就是undefined
         注意:  如果函数内没有return,则函数调用的返回值也是undefined
              function fn(n) {
                console.log( n+10 ) 
              }
              // 函数调用也是一个表达式,执行后会有结果          
              var res = fn(10);// 将函数调用的结果 赋值给变量res
              console.log( res ) //  undefined