05 JS中的函数

121 阅读8分钟

1.函数的概念

在JS中,函数可以理解为一段在程序(页面)中 多次出现的代码段 封装起来的盒子

简单来说,JS的函数就是一个盒子,盒子里面装的是 在当前页面中 多次出现的 较为复杂的代码段

2.函数的使用

  1. 函数的定义(创建一个所谓的盒子)
  • 声明式定义

语法: function fn(){}

 function:关键字 -> 表明后续的是一段函数
 fn: 函数的名字 -> 将来函数调用的时候需要用到,函数名自定义
 (): 内部填写参数
 {}: 内部填写函数调用时要执行的代码段
 
 function fn1(){
    console.log('我是fn1函数')
  }
  • 赋值式定义

语法: var fn = function(){}

var fn2 = function(){
   console.log('我是fn2函数')
}
  1. 函数的调用(使用盒子内的代码) 如果函数只定义不调用那么没有任何意义
  • 调用语法: 函数名() / 变量名()
 fn1()
 fn2()
 //间隔500行代码
 fn1()
  1. 声明式和赋值式的区别
  • 写法不同
  • 调用上略有不同
  1. 声明式定义的函数,可以在函数定义前去调用
  2. 赋值式定义的函数,不可以在函数定义前去调用(原因:赋值式定义,其实就是声明一个变量,然后给他赋值为一个函数.在JS中,如果在定义变量之前使用变量的话,那么变量的值为undefined(变量提升))

3.函数的参数

  1. 函数的参数如何书写?

书写在function后的小括号内

  1. 参数的作用?如果一个函数没有书写参数,那么这个函数的功能相对来说比较单一;如果书写了参数,能够使我们这个函数的使用更加灵活

参数的书写,分为两个

  • 1.function后的小括号内 书写的参数我们叫做"形参"

    形参的作用:书写之后,相当于在函数内部创建了一个变量,变量实际的值由"实参"传递

  • 2.函数名后的小括号内 书写的参数我们叫做"实参"

    实参的作用:将自身的值,按照一一对应的关系,传递给形参

   function fn2(a,b){
    var sum = a + b
    console.log(sum)
   }
   fn2(10,20)
   //新需求:计算300+400的值
   fn2(300,400)
  1. 函数的参数的注意事项:形参和实参 两个的数量,要一一对应
  • 1.形参的数量如果大于实参:会将实参按照顺序一一传递给对应的形参;多出来的形参,相当于变量只定义没赋值,所以他们的值是undefined
  • 2.实参的数量如果大于形参:会将实参按照顺序一一传递给对应的形参,多出来的实参无法在函数内部通过参数的方式调用
   function fn(a,b,c,d){
    console.log(a,b,c,d)
   }
   fn(1,2) //1,2,undefined,undefined

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

4.函数的返回值(函数的执行结果)

JS有一个规定,在函数内部定义的变量只能在函数内部使用,我们如果想在函数外部得到函数内部的某一个值,或者运算结果,我们可以通过return这个关键字来帮我们完成

  function fn(a,b){
    var sum = a + b
    //书写返回值
    return sum
  }
  //创建变量 接收函数的返回值
  var num = fn(100,200)
  console.log('num的值:',num) //300
  • return的注意事项

    return具有中断函数的能力,所以一般来说我们将它放在函数的尾部

5.函数案例

5.1要求封装一个函数,这个函数能够计算一个区间内所有数字相加的合

   function fn(start,end){
    //计算1-100之间所有数字的和
    var sum = 0
    for(var i = start; i <= end; i++){
      sum += i
    }
    return sum 
   }
   var num = fn(1,100)
   console.log(num) //5050

5.2判断一个数字!!!是否为水仙花数,是水仙花数,返回一个true,否则返回false

 function fn(i){
  var baiW = parseInt(i/100)
  var shiW = parseInt(i/10%10)
  var geW = i % 10
  var sum = baiW*baiW*baiW+shiW*shiW*shiW+geW*geW*geW

  if(sum===i){
    return true
  }else{
    return false
  }
 }
 fn(153)
 var re = fn(152)
 console.log(re) //true

6.函数的预解析

预解析的一个表现就是 声明式函数在定义前可以被调用
预解析是什么?
   JS在执行代码的时候,会有一个所谓的解析阶段,解析阶段,做了一件事,就是函数提升,就是将声明式函数的定义,提升到当前作用域的最顶端
   fn()
   function fn(){
     close.log('我是 fn 函数,我被调用了')
   }
   预解析之后的代码:
   function fn(){
    close.log('我是 fn 函数,我被调用了')
   }
   fn() //所以此时调用的时候,因为fn 函数已经定义完成了,所以这里能够正常执行函数

7.作用域

  • 什么是作用域?

    就是变量可以起作用的范围

  • 作用域分为哪些?

1.全局作用域(直接在script内书写的代码)

在此作用域创建的变量,我们叫做全局变量,在当前script标签内的哪里都能使用
在JS中,全局作用域中有一个提前给我们准备好的 对象,这个对象叫做 window,我们创建的全局变量,会被自动添加到window对象中

2.局部作用域(在JS中,只有函数能够创建局部作用域)

在此作用域创建的变量,只能在当前作用域使用,超出这个作用域(也就是在函数外边)去使用,就会找不到变量 复制代码

   function fn(){
    var sum = '我是在函数内部创建的文件,我是局部变量,所以我只能在当前函数内使用'

    var abc123 = '我实在fn函数内部创建的局部变量'
    console.log(sum)
   }
   fn()
  //  console.log(sum)//这里因为超出了这个变量的使用区间,所以会报错


  var abc = '我是一个全局变量abc'//创建一个全局变量abc

  console.log(window)

8.作用域链

  1. 概念

作用域链就是在访问一个变量的时候,如果当前作用域内没有,会去自己的父级作用域,也就是上一层作用域内查找,如果找到就直接使用,如果没有找到继续向上层查找,直到查找到 最顶层的全局作用域,如果找到了直接使用,如果没有找到,报错提示变量不存在(未定义),我们将这个一层一层向上查找的规律,叫做作用域链.

   var num = 999
   function fn1(){
    var num = 100
    function fn2(){
      console.log(num)
      /**
       * 打印的值为100
       *     1.现在现在当前作用域内,也就是 fn2 函数内部开始查变量 num,然后发现 当前作用域内 没有这个变量 所以会去自己的父级的作用域内查找( 也就是 fn1 这个函数内部)
       *     2.来到了自己的父级内部查找,此时找到了一个变量num 他的值为100,然后直接使用这个变量
      */
     }
    fn2()
    }
    fn1()
   var num = 999
   function fn1(){
    function fn2(){
      console.log(num)
      /**
       * 打印的值为999
       *     1.现在现在当前作用域内,也就是 fn2 函数内部开始查变量 num,然后发现 当前作用域内 没有这个变量 所以会去自己的父级的作用域内查找( 也就是 fn1 这个函数内部)
       *     2.来到全局作用城内查找的时候 发现了一个叫 num 的变量值为 999,然后停止查找,直接使用该变量
      */
     }
    fn2()
    }
    fn1()
  1. 作用域链的赋值规则 在给变量赋值的时候,首先会去当前作用域内查找该变量,如果有,直接赋值,并停止查找;如果没有,会去自己的父级查找,在父级找到直接修改然后停止查找,如果没有继续向自己的父级查找,直到找到全局作用域,在全局作用域内,找到直接赋值修改他的值,如果没有找到,那么会在全局作用域创建一个变量,并赋值.
   function fn1(){
    var num = 999
    function fn2(){
        num = 100
        /**
         * 在当前作用域内查找,发现没有,会去自己的父级作用域内查找也就是fn1函数内部
         *  在fn1函数内部发现一个变量num 然后值为999  我们会对这个变量做一个重新赋值的操作
         *   也就是将他的值 重新修改为100
        */
     }
     fn2()
     console.log(num)//100
    }
    fn1()

9.递归函数

当一个函数在函数的内部,调用了自身,那么就算是一个所谓的递归函数(只不过有点小缺陷)

  function fn(n){
    if(n === 1){
      //说明此时想要计算1的阶乘,那么我直接将1的阶乘的结果return出去
      return 1
    }
      return n * fn(n - 1)
   }
   var sum = fn(4)
   console.log(sum) // 24

   var sum1 = fn(100)
   console.log(sum1)