js函数

344 阅读10分钟

1.函数介绍

函数是一个数据类型,可以理解为存储代码的容器

2.函数语法

      1.声明函数 : 是一个存储过程,只是把代码存起来,不会执行函数体代码  
          function 函数名(){
              函数体代码: 需要存储的一段代码
          }

      2.调用函数 : 执行函数体代码
          函数名()
          

3.函数和循环区别:

    1.本质区别
    函数是一种数据类型:负责存储代码
    循环是一种语句:让一段代码执行多次
    2.功能不同
    函数:代码复用(一段代码需要在很多个地方执行一次)
    循环:重复执行(一段代码在一个地方执行多次)
    

4.函数参数

    函数语法  : 函数是一种用于存储代码块的复杂数据类型
    作用:解决代码复用问题
    
     1. 声明函数 :  *****声明函数只是存代码, 不会执行函数体*****
        function 函数名(){
            函数体
        }

    2. 调用函数 : 执行函数体代码
        函数名()

    3. 函数参数 : 调用者数据 传递 函数
        3.1 传 : 调用者
            函数名( 实参 )
        3.2 收 : 函数
            function 函数名( 形参 ){  函数体 }
        3.3 函数传参原理 : 实参 给 形参赋值
        3.4 注意点
            a. 实参和形参数量可以 不一致,但是按照顺序一一赋值

案例:

  function learn(name, money) {
        console.log(`1-${name}来武汉学习前端`);
        console.log(`2-${name}学习前端`);
        console.log(`3-毕业了`);
        console.log(`4-${name}找到月薪${money}的工作`);

    }
    //调用者A:班长
    
      learn('班长', 16000) 
      
    //调用者B:小明
    
      learn('小明', 12000)
      
    //调用者C:小刚
    
      learn('小刚', 13000)
      
    //调用者D:班长小迷妹
    //每一个调用者,调用函数的时候都是独立的过程.互不影响.
    
        learn() // learn(undefined,undefined)
        

image.png

5.需求:声明一个函数,可以求任意两个数字的和

    function sum(num1, num2) {
        let sum = num1 + num2
        console.log(sum);
    }
    sum(10, 20)  
    

6.函数默认参数

函数默认参数 使用 逻辑运算符短路运算(逻辑中断)
当逻辑表达式,左边的式子就可以决定结果,右边的式子不会执行
2.1 短路运算: 左边式子就可以决定结果,右边式子不执行
     && : 一假则假
     || : 一真则真
     ! : 取反(没有短路运算,因为只有一个式子)
2.2 短路规则:
&& : 找假。 左边式子值可以转成false,则无条件返回左边式子的值,右边不执行。反之无条件返回右边式子的值。
|| : 找真。左边式子值可以转成true,则无条件返回左边式子的值,右边不执行。反之无条件返回右边式子的值。
逻辑中断应用:
函数默认参数
复杂筛选功能
逻辑中断:当逻辑运算符左边的式子就可以决定结果.此时右边式子不执行
    let num =10
    let res = 1 > 10 && num++
    console.log(res)//false
    console.log(num)//10
 逻辑与 : 一假则假
 短路规则:找假.左边式子可以转成false,得到左边式子的值.反之得到右边式子的值
    let res = 1 && null
    console.log(res) //null
 逻辑或:一真则真
 短路规则:找真.左边式子可以转成true,得到左边式子的值.反之得到右边式子的值
    逻辑非!没有短路运算.因为:逻辑非只有一个式子
    console.log(1 && unfefined && null) //unfefined
    console.log(1 || unfefined || null) //1
    
    //应用场景1 : 函数默认参数
  function getSum(num1,num2){
    num1 = num1 || 10
    num2 = num2 || 20
    let sum = num1+num2
    console.log( sum )//21
  }

  getSum(1)
    

7.需求:声明一个函数,可以求任意数组中 每一个元素的和

    function getSum(arr) {
        let sum = 0
        for (let i = 0; i < arr.length; i++)
            sum += arr[i]
        console.log(sum);
    }
    getSum([10, 20, 30])
    

8.函数返回值return

   .函数返回值 : 函数 传递数据将运算结果返回 给调用者
   4.1 传 : 函数
     function 函数名(){//函数体 return 返回值 }
     
   4.2 收 :  调用者
      let 变量名 = 函数名()
          
function getSum(arr) {
    let sum = 0
    for (let i = 0; i < arr.length; i++) {
      sum += arr[i]
    }
    //返回值
    return sum
  }

  /* 函数工作流程 : 
  1.传参 : 调用者 ->  函数
  2.执行函数体
  3.返回值 : 函数 -> 调用者
  */
  //购物车页面 : 将运算结果显示在button标签中
  let sum1 = getSum([10,20,30,40,50])
  document.write(`<button>${sum1}</button>`)
  
  //订单页面 : 将运算结果显示在h2标签中
  let sum2 = getSum([80,20,66,50])
  document.write(`<h2>${sum2}</h2>`)
       

image.png

 4.3 return注意点
     (1)函数return关键字后面的代码不会执行的
        * 只要有return关键字,函数体立即结束执行。
        类似于break关键字 break是结束循环体 return是结束函数体 
     (2)如果函数没有return,则默认返回值是undefined
          函数工作流程
     (3)如果函数有return,但是return后面没有值.此时黙认也是undefined
        return关键字可以单使用,作用是结束函数
             

image.png

image.png

  /* 为什么要有返回值 : 实际开发中,每一个调用者调用函数之后,得到的运算结果。 处理方式不同的。
  如果在函数内部处理 函数运算结果,那么所有的调用者处理方式都相同。 无法实现需求。
  正确做法 : 函数自己不处理结果,而是把运算结果 返回 给调用者。 由调用者决定如何处理。
  */
  

函数工作流程

image.png

9.写一个函数,求数组的和

    //声明函数    
    function getSum(arr){
        let sum = 0
        for(let i =0;i<arr.length;i++){
            sum += arr[i]
        }
        //返回值
        return sum
    }    
    //调用者A
    let num1 = getSum([10,20,30,40,50])
    document.write( `<a href="#">${num1}</a>` )
    //调用者B
    let num2 = getSum([80,20,55,66])
    document.write(`<button>${num2}</button>`)
    

10.需求:声明一个函数,求任意数组最大值并返回这个最大值

  function getMax(arr) {
        let max = arr[0]
        for (let i = 1; i < arr.length; i++) {
            if (arr[i] > max)
                max = arr[i]
        }
        return max
    }
    let arr1 = getMax([20, 30, 50, 40, 10])
    console.log(arr1);

11..需求:声明一个函数,求任意数组最小值并返回这个最小值

      function getArrMin(arr1) {
        let min = arr1[0]
      for (let i = 1; i < arr1.length; i++) {
        if (arr1[i] < min) {
        min = arr1[i]
      }
    }
     return min
   }
    const re = getArrMin([10, 20, 3, 40, 50])
    document.write(re)

12.任意输入两个数,比较这两个数的大小

方法一:
 let num1 = +prompt('请输入第一个数字')
 let num2 = +prompt('请输入第一个数字')
  function getMax(num1,num2) {
       if(num1>num2){
       return(num1)
    }else{
    return(num2)
    }
    }
    let arr1 = getMax(num1,num2)
    alert(arr1)
方法二:
     let num1 = +prompt('请输入第一个数字')
     let num2 = +prompt('请输入第一个数字')
   function getMax(num1,num2) {
      return num1>num2?num1:num2
    }
    const arr1 = getMax(num1,num2)
    document.write(arr1)

13.封装一个函数,可以求任意数组的和 或 平均值

   // **要求:**
// - 函数可以传递2个参数,比如  handleData(arr, true)      `handleData 处理数据的意思`
//   * 参数一: 接受实参传递过来的数组
// * 参数二:  布尔类型  如果是true或者不传递参数 是求和操作,   如果传递过来的参数是 false 则是求平均值
const arr = [10, 20, 30, 40, 50]
//封装一个函数
function handleData(arr, flag = true) {
  //声明一个变量
  let sum = 0
  //循环数组
  for (let i = 0; i < arr.length; i++) {
    sum += arr[i]
  }
  if (flag === true) {
    document.write(sum)
  } else {
    document.write(sum / arr.length)

  }
}
handleData(arr)

14.需求:声明一个函数,求任意数组最大值以及最小值

   function getArr(arr) {
      let max = arr[0]
      let min = arr[0]
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] > max) max = arr[i]
    if (arr[i] < min) min = arr[i]
  }
  return [max, min]
}
const res = getArr([2, 6, 8, 12, 10])
console.log(res)

15.需求: 用户输入秒数,可以自动转换为时分秒

 const seconds = +prompt('请输入秒数')
    function formatDate(res) {
       //计算时分秒
        let h = parseInt(res / 60 / 60 % 24)
        let m = parseInt(res / 60 % 60)
        let s = parseInt(res % 60)
        //数字小于10补0
        h = h < 10 ? '0' + h : h
        m = m < 10 ? '0' + m : m
        s = s < 10 ? '0' + s : s
  return `${h}:${m}:${s}`
 }
const re = formatDate(seconds)
document.write(re)

16.写一个函数:判断数组是不是所有元素都是正数, 是则返回true 否则返回false

  /* 本案例除了锻炼函数所有语法之外,还加强逻辑思维锻炼
    1.累加和 : 购物车求和
    2.最大值 :  找出最大的值
    3.开关思想 :  判断数组中是否 所有元素 都满足条件
        应用场景: 购物车勾选功能。 当每一件商品全部勾选,全选按钮也要勾上。
                 (判断商品数组中是否所有的元素都勾上了)

    开关思想流程 : 
      (1)声明布尔类型数据存储结果 (一般给默认值true)
          let bol = true
      (2)遍历数组,检查是否满足布尔条件. 如果遇到不满足的,则修改布尔值为false
      (3)获取布尔值结果     
  */
  
  
  
//为什么要声明布尔类型?
//答:因为需求是判断是不是正数,只有true和false两种情况
    function isAllPositive( arr ){
       //(1)声明变量存储结果
          let bol = true
       //(2)遍历数组,检查是否满足布尔条件. 如果遇到不满足的,则修改布尔值为false
    for(let i = 0;i<arr.length;i++){
      if( arr[i] < 0 ){
        bol = false
        break//一旦找到负数,后面的循环就没有必要执行。 可以提高循环执行效率
      }
    }
    //(3)获取开关结果
    return bol
  }

  let res1 = isAllPositive( [10,20,30,40,50] )
  console.log( res1 )//true
  let res2 = isAllPositive( [10,20,-30,40,50] )
  console.log( res2 )//false

17.需求:写一个函数,找任意数组中有没有10. 如果有则返回10的下标,没有则返回-1

   /* 本案例除了锻炼函数所有语法之外,还加强逻辑思维锻炼
        1.本案例所采用的思想称之为:开关思想
        2.开关思想用于解决此类问题 : 判断数组中是否所有元素满足条件
        3.开关思想主要分为三个流程
           (1)声明一个开关变量(一般默认为true)
           (2)遍历数组,判断每一个元素是否满足条件,遇到不满足修改开关变量为false
              * 遇到满足的不用修改,因为默认就是true
           (3)返回开关变量值
  */
  
    function isAllNum(arr) {
     //(1)声明变量存储结果
    let bol = -1 // 没有10
     //(2)遍历数组,找不满足条件的
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] == 10) {
        bol = i
        break
      }
    }
     //(3)获取开关结果
    return bol
  }

  let res1 = isAllNum([1, 2, 3, 4, 5])
  console.log(res1)

  let res2 = isAllNum([1, 2, 10, 4, 5])
  console.log(res2)
  

image.png

18.作用域

   /* 
     1.js变量作用域:  变量可以使用的范围
        
     2.js三种作用域:
        2.1 全局作用域 : 页面任何地方都可以使用
            全局变量 : 在大括号外面声明的变量
        2.2 局部作用域 : 只能在函数大括号里面使用
        2.3 块级作用域 : 只能在大括号(if和for)里面使用
        
    */

    //全局作用域 : 全局变量
    let num = 10

    //局部作用域 : 函数里面声明的变量
    function fn(a){//形参也是局部
        //局部变量
        let age = 20
        console.log(age)    
    }
    fn(10)

    //块级作用域: 在大括号里面声明的变量(分支+循环)
    for(let i = 1;i<=10;i++){
        //块级变量
        console.log( i)
    }
    

image.png

image.png

19.js作用域链

 js作用域链 : 默认情况下,js代码处于全局作用域(顶级/0级),
 当声明函数之后就会开辟一个局部作用域(1级), 而函数内部又可以声明一个函数(2级),
 以此类推就会形成作用域链。

     4.js访问作用域链规则 : 就近原则
      * 当你访问变量的时候,会先在当前作用域寻找声明。 有则使用当前作用域。
      没有就找上级有没有声明,有则使用,无则继续往上找。一直找到最顶级0级,
      还没有就会报错:xxx is not defined
    */

    //0级
    let num = 10
    console.log( num )//10
    
    function fn(){
      //1级
      let num = 20
      console.log( num )//20

      function fn1(){
        //2级
        let num = 30
        console.log( num )//20
      }

      fn1()
    }

    fn()

image.png

19-1

image.png

image.png

20.匿名函数

        /* 
    1.匿名函数 :  没有函数名的函数
    2.匿名函数作用 :  开辟独立作用域,解决全局变量污染
        变量污染 : 全局变量名过多之后,就会导致重名风险。
    */

    //具名函数(有名字的函数) :  function 函数名(){} 
    // 具名函数调用语法:  函数名()
    function fn(){
        console.log(1111)
    }
    fn()

    //匿名函数(没有名字的函数) :  function(){}
    // 匿名函数由于没有函数名,所以不能直接调用。调用匿名函数,只有两种方式
    /* 
    (1)函数自调用 :  (匿名函数)()
        * 细节: 自调用语法前面不能省略分号
    (2) let 函数名 = 匿名函数
    */
    
    匿名函数调用的两种方法:
     (1)函数自调用 :  (匿名函数)()
        * 细节: 自调用语法前面不能省略分号
    ;(function(){
       let num = 10
       console.log(num)
    })()

    (2) let 函数名 = 匿名函数
    let fn1 = function(){
        console.log(666)
    }
    fn1()
    

image.png