• 04-JS函数


    一、函数类型的认识

    1. 函数的概念

      函数是具备某个功能的工具,是完成某个功能的一段代码

    2. 函数的定义及调用

      // 第一种定义方法:声明式/直接创建式
      // 定义
      function 函数名(){
          代码段
      }
      //调用
      函数名()
      
      // 第二种定义方法:赋值式/匿名函数
      // 定义
      var 变量名 = function(){
          代码段
      }
      // 调用
      变量名()
      
      // 案例:定义函数求两个数字的和
      function fn(){
          var a = 1,b = 2,c = a+b;
          console.log(c);
      }
      fn();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      函数的注意点:

      1. 注意单词、格式、语法、符号
      2. 注意执行函数的位置,不同的创建方式可执行的位置不同
      3. 注意行为调用函数时的格式
      4. 注意不要概念复杂化

      函数的优点:

      1. 实现了代码的可重用性
      2. 实现了模块化编程

      函数的调用执行拓展:通过事件来调用匿名函数(绑定事件)

      <body>
          <button onclick="fn()">点击调用函数button>
      body>
      <script>
          function fn(){
              var a = Number(prompt("输入第一个数"))
              var b = Number(prompt("输入第二个数"))
              alert(a+b)
          }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    二、函数的参数应用

    function fn(a){//形参:形式上的参数
        console.log(a)
    }
    fn(10)//实参:实际上的参数
    
    //需要根据参数不同显示不同的乘法表
    function fn(num) {
        document.write('')for(var i =1; i <= num; i++){
            document.write('')for(var j =1; j <= i; j++){
                document.write('')}
            document.write('')}
        document.write('
    ' + j + 'x' + i + "=" + i * j + '
    '
    ) } var num=Number(prompt("输入一个数字")) fn(num)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    参数的概念

    1. 形参:形式参数,作用是接收参数
    2. 实参:真实参数,作用是传递参数

    参数使用注意点

    1. 函数的参数有多个的时候,需要用逗号隔开
    2. 在形参中书写变量,表示在函数体内声明了变量,此时还没有赋值,数据类型为undefined
    3. 当传入实参的时候,表示给形参的变量赋值

    参数数量的问题

    1. 原则上,函数的形参和实参的个数和数据类型都要一一对应的
    2. 如果实参的数量比形参数量少,从左到右依次选择,没有参数的形参默认是undefined
    3. 如果实参的数量比形参数量多,从左到右依次选择,多的形参对函数体内的结果不产生任意的影响,但此时函数会默认提供一个内置对象

    函数内置对象的拓展【类数组/伪数组】

    1. arguments.length 获取传入参数的个数
    2. arguments[索引] 通过索引获取对应的参数

    三、函数的返回值

    函数运行结束之后得到的结果

    // 案例1:定义一个让指定数字递增的函数
    function increase(x){
        var y = x+1;
        return y//return 程序结束后,后面的代码就不会执行了
    }
    
    // 1. 让2递增,得到的结果赋值给变量a
    var a = increase(2);
    document.write(a%2);//1
    
    // 2. 让5递增,得到的结果赋值给变量b
    var b = increase(5);
    alert(b/2);//3
    
    // 3. 让10递增,得到的结果赋值给c
    var c = increase(10);
    console.log(c+a-b);//11+3-6 = 8
    
    // 案例2:定义三个变量,先求和再求平均数
    var a = Number(prompt("输入第一个数"))
    var b = Number(prompt("输入第二个数"))
    var c = Number(prompt("输入第三个数"))
    
    function sum(a,b,c){
        return (a+b+c)
    }
    function avg(a,b,c){
        return (a+b+c)/3
    }
    
    document.write('和是'+sum(a,b,c)+'
    '
    ) document.write('平均是'+avg(a,b,c))
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    函数的嵌套【拓展】

    1. 由于函数的调用可以写在页面的任意地方,在另外一个函数里面调用执行一个函数也可行

    2. 用函数嵌套的方式实现上面的案例2

      function sum(a,b,c){
          return (a+b+c)
      }
      function avg(a,b,c){
          document.write('和是'+sum(a,b,c)+'
      '
      ) return (a+b+c)/3 } document.write('平均是'+avg(a,b,c))
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    四、函数的预解析

    1. 浏览器中有一段程序专门用来解析JS代码,叫做JS解析器。js解析器在执行js代码的时候,分两步进行:

      1. 预解析js代码:预解析的过程,就是查找代码中的var和function这两个关键字,找到以后,将变量和函数存在了一个地方,并给他们赋一个初始值,变量的初始值为undefined,函数的初始值为代码段
      2. 开始按顺序一行一行解读代码:解读代码的时候,仓库中的变量和函数的值会随着代码的解读而发生变化,也就是变量的赋值和函数的调用
    2. 预解析分为变量的预解析和函数的预解析,也就是代码在执行之前先进行解析,这步是不可见的

    3. 总结:预解析就是将变量和函数的声明放在当前作用域的最前面,也可以叫做变量提升

      变量赋值和函数的调用保留在原来的位置不动,其他代码正常运行

    // 案例1:变量提升
    console.log(a)
    var a = 10
    //undefined  提升的是定义,不是赋值
    
    // 案例2:声明式函数提升
    fn()
    function fn(){
        console.log('Hello')
    }
    //正常输出
    
    // 案例3:赋值式函数提升
    fn()
    var fn = function(){
        console.log('Hello')
    }
    //报错 提升的是var fn,没有赋值。调用fn()的时候报错,不会再往下运行
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    变量提升总结:

    1. 用var关键字声明的变量,将变量的声明提升到当前作用域的最前面,赋值不提升
    2. 自定义的函数整体提升到当前作用域的最前面
    3. 函数同名,后面的会覆盖前面的
    4. 变量和函数同名,函数优先提升
    // 第一题
    console.log(fn)
    fn()
    var fn = function(){
    	console.log(123)
    }
    // undefined,报错
    // 赋值函数,提升的是var fn,此时fn是undefined
    
    // 第二题
    fun()
    var fn = function(){
        console.log('我是fn')
    }
    function fun(){
        console.log('我是fun')
    }
    fn()
    fn = 100
    fn()
    // 我是fun,我是fn,报错(fn赋值了100,不是函数了)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    五、函数的作用域

    1. 全局作用域:不在任何函数中
    2. 局部作用域:在函数的内部中
    1. 局部作用域
    function fn(){
        var a = 1//局部变量
        console.log(a) //1
    }
    fn()
    console.log(a)//在函数体的外面,并没有声明定义a变量,所以得到的结果就是报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    局部作用域总结:

    1. 在函数内部定义的变量叫做局部变量,只能在函数内部使用
    2. 全局变量不可以访问局部变量
    2. 全局作用域
    var b = 1 //全局变量
    function fn(){
        var b = 2 //局部变量
    }
    fn()
    console.log(b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    全局作用域总结:

    1. 在函数外面定义的变量叫做全局变量
    2. 当函数内部声明变量没有使用var的时候,情况比较特殊
    1. 特殊情况

      //特殊情况:函数内部声明的变量也是全局变量
      var c=1
      function fn(){
          c=2//当函数内部声明没有使用关键字的时候是会往上级查找的,可以理解为是全局变量
          //这种声明方式是“隐式声明”
      }
      console.log(c)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    六、函数访问赋值规则

    1. 访问规则
    function f1(){
        var a = 2
        function f2(){
            console.log(a)//2
        }
        f2()
    }
    f1()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    访问规则的总结

    1. 如果当前作用域有定义的时候就会直接使用当前作用域的变量
    2. 如果当前作用域没有定义就会往上级查找,上级没有就继续往上,直到找到全局
    3. 如果全局有就输出,没有就报错
    2. 赋值规则
    //案例1
    function f1(){
        function f2(){
            a = 1
            //1. 加了var关键字代表局部变量
            //2,不加var关键字 隐式声明,全局作用域
        }
        f2()
    }
    f1()
    console.log(a)
    
    //案例2
    function f1(){
        var a = 1
        function f2(){
            a = 2
            console.log(a)
        }
        f2()
        console.log(a)
    }
    f1()
    console.log(a)
    // 2 2 报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    赋值规则总结

    1. 往上级查找,上级存在可以重新赋值,上级没有就一直往全局查找
    2. 如果全局有就使用全局中的变量
    3. 如果全局没有定义变量,查找到全局的时候,会自己在全局定义一个变量
    // 练习1
    var num = 10;
    fn1();
    function fn1(){
        console.log(num);
        var num = 20;
    }
    //undefined
    
    // 练习2
    fn2();
    var a = 18;
    function fn2(){
        var b = 9;
        console.log(a);
        console.log(b);
    }
    // 练习2 预解析过程
    var a
    function fn2(){
        var b 
        b=9
        console.log(a)
        console.log(b)
    }
    fn2()
    a=18
    //undefined 9
    // 如果a的赋值在函数调用之前,就会是18
    
    // 练习3
    fn3();
    console.log(c);
    console.log(b);
    console.log(a);
    function fn3(){
        var a=b=c=9;
        console.log(a);
        console.log(b);
        console.log(c);
    }
    // var a=b=c=9; 理解为 var a=9;b=9;c=9 所以a是局部作用域
    //9 9 9 9 9 报错
    
    // 练习4
    var a = 4;
    console.log(a);
    a = 6
    console.log(a);
    
    function a(){
        console.log('哈');
    }
    a();
    a = 10;
    console.log(a);
    // 练习4 预解析 
    var a
    function a(){
        console.log('哈')
    }
    a=4
    console.log(a);
    a=6
    console.log(a);
    a();//此时a是6 以函数的方式调用,会报错
    a=10;
    console.log(a)
    // 4 6 报错
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    七、递归函数

    1. 在函数中调用自己
    2. 类似于循环
    3. 使用递归函数要注意返回,否则会造成死递归
    4. 递归比较消耗性能,尽量少用
    //递归的语法
    function fn(){
        fn()
    }
    fn()
    
    //常见的递归
    function fn(a){
        if(a==1){
            return 1
        }
        return fn(a-1)
    }
    var res = fn(10)
    console.log(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    //案例1:使用递归求1-5的和
    function fn(a){
        if(a==1){
            return 1
        }
        return (a+fn(a-1))
    }
    var res = fn(5)
    console.log(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    // 案例2:斐波那契数列
    function fn(a){
        if(a==1||a==2){
            return 1;
        }
        return fn(a-1) + fn(a-2)
    }
    var res=fn(10)
    console.log(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    八、事件的了解

    事件触发函数

    <body>
        <button id="btn1">
            声明式函数触发
        button>
        <button id="btn2">
            赋值式函数触发
        button>
    body>
    <script>
        //声明式函数触发
        function fn(){
            alert("我是声明式函数")
        }
        btn1.onclick=fn
        //赋值式函数触发
        btn2.onclick=fn(){
            alert("我是赋值式函数")
        }
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    <body>
        <input type="text" placeholder="请输入一个数">
        <button>
            计算
        button>
        
    body>
    <script>
    // 案例:触发事件求阶乘
    // 1. 计算阶乘;2. 给标签绑定id,事件方式触发函数;3. 获取用户输入的值 DOM.value
        function fn(num){
            if(num == 1){
                return 1
            }
            return num * fn(num-1)
        }
    	fn(5)
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    九、对象数据类型

    对象的概念:用来储存数据,可以理解为容器

    1. 对象的表现形式
    var obj = {} //对象
    var arr = [] //数组
    var none = null //空
    
    • 1
    • 2
    • 3
    2. 对象的创建方式
    //第一种:声明式/直接创建式
    var obj = {}
    
    //第二种:构造函数方式/new方式
    var obj = new Object()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    3. 对象存储数据的格式
    //第一种:声明式/直接创建式
    var obj = {1:1,2:2,
        ...
    }
    
    //第二种:构造函数方式
    var obj = new Object({1:1,2:2,
        ...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    对象存储数据的语法规则:键值对

    1. 键(key):也叫做对象的属性,必须是字符串,但是这个字符串在不包含连字符的时候可以不加引号,建议加上。如果键有多个单词有连接符的时候,要注意加上“”,或者使用驼峰命名
    2. 值(value):可以是任意类型,包括:数字、字符串、布尔、对象、函数
    3. 键值对之间使用逗号隔开
    4. 键值对之间没有顺序,是一个无序的数据集合
    4. 对象的访问
    var person = {
        "name":"小明",
        "age":10,
        "background-color":"green"
    }
    console.log(person.name,person.age)
    console.log(person['name'],person['age'],person['background-color'])
    console.log(preson['aa'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    对象访问的注意点

    1. 两种方式都可以访问对象中的数据,通过键获取得到的就是键值对的值
    2. 对象.键 这种的获取方式,如果键有连接符号的时候会报错,获取不到
    3. 如果键有连接符号的时候,需要使用 对象[“键”] 这种方法获取
    4. 对象中没有这个键的时候,返回的是undefined
    5. 对象的遍历
    for(var attr in obj){
        //输出需要的数据
        console.log(attr)
        console.log(attr[i])
    }
    //attr表示对象属性名,obj表示这个对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    对象遍历的注意点

    1. 遍历出来的数据是一个变量 对象.键 这种方式获取不到
    2. 遍历出来的数据是一个变量 对象[键] 这种方式是可以获取得到的,并且引号不用添加
    3. 如果使用for in这种方式遍历对象的话,建议使用 对象[键] 这种方式进行获取数据
    6. 对象的方法
    1. 对象中的值可以是任意的数据类型
    2. 值可以是一个对象,还可以是一个函数(function=>方法)
    //1.定义一个对象
    var person = {
        name:'小明',
        age:26,
        sex:'男',
        // 2. 在对象中再嵌套一个对象
        brother:{
            name:'大明',
            age:30,
        }
        // 3. 对象中的值还可以是一个函数,可以理解为对象中的方法
        eat:function(){
            console.log("吃饭")
        }
        
    }
    
    console.log(person.brother.name)
    //1. 之前调用函数的方法是:函数名称()
    //2. 在对象中调用函数方法:键值对中的键()
    person.eat()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    7. 对象的操作
    1. 增加 对象.键的名字 = 值
    2. 修改 对象.键的名字 = 值
    3. 删除 delete 对象.键的名字
    4. 查询 对象.键的名字 || 对象[‘键的名字’]
    var obj = {
        name = '小明',
        age = 18,
        gender = '女'
    }
    obj.money = 0 //增加
    obj.money = 2000 //修改
    delete obj.money //删除
    obj = {} //置空
    for(var i in obj){ //置空
        delete obj[i]
    }
    console.log(obj)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    8. 构造函数【拓展】

    只要使用了new方式创建的方法都是构造函数。任意的数据类型都可以用构造函数去创建

    //1.使用构造函数创建对象
    var obj = new Object()
    console.log(obj)
    
    //2.利用构造函数方式创建函数
    function Fn(){}
    var a = new Fn()
    console.log(a)
    
    //3.利用构造函数创建数据类型
    var num = new Number()
    console.log(num)
    
    //指向window 默认情况下,this指向全局
    console.log(this)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    总结:关于构造函数和普通函数的区别

    1. 有没有new关键字
    2. 关于this指向的问题
    3. 首字母是否大写是区别构造函数和普通函数的最直观的表现
  • 相关阅读:
    windows彻底卸载unity
    stable diffusion如何解决gradio外链无法开启的问题
    Vue业务组件封装(二)Form表单
    springboot冬奥会竞赛项目知识网站的设计与实现毕业设计源码152337
    软考的网络工程师对就业有用吗?
    说大话还是真实力,Rust是被炒“火”的吗
    【一、灵犀考试系统项目设计、框架搭建】
    VR直播系统设置大揭秘,带你穿越时空亲临现场
    springboot源码理解四、自动配置(项目根目录下的bean)
    用户登录问题
  • 原文地址:https://blog.csdn.net/qq_41570386/article/details/127627434