函数

## 1.函数的概念

 

- 空调:由遥控器或开关控制,可以实现调解空气的功能的家用电器

 

- 函数:由用户或自身控制,可以实现某个功能的 代码段(很多代码)

 

- 家用电器(空调)的特点:

    - 忽略细节

    - 重复使用

    - 选择使用

 

- 函数的特点:

    - 忽略细节:在**使用过程**中,只需要关注其实现的功能,而不需要关注其内部原理

    - 重复使用:多次使用

    - 选择使用:按需使用

 

## 2.创建函数

- 函数从哪来

    - 内置(系统提供,公司发的)

        - `parseInt()`

        - `parseFloat()`

        - `alert()`

 

    - 自定义(自己写,自己给自己做)

        - 声明式创建函数

            - 需要配合关键字:`function`

            - 语法:

                ```js

                    function 函数名(){}

                ```

        - 赋值式创建函数

            - 需要配合关键字:`var`和`function`

                ```js

                    var 变量名 = function(){}

                ```

        - 函数其实就是一个变量,只不过内部存的是一段代码,这段代码还被一个容器包裹了


 

## 3.执行函数

- 函数名()

    - 只要函数名后面有小括号,必然会立即执行**当前**函数

    - 固定语法

- 通过事件执行

    - 执行无名函数

    ```js

        元素.事件 = function(){}

    ```

    - 执行有名函数

    ```js

        元素.事件 = 函数名

    ```

    - 无名函数配合有名函数,使用较多

    ```js

        元素.事件 = function(){

            函数|变量名()

        }

    ```

 

## 4.函数分类

- 根据写法分类

    - 有名函数:

        - 正常函数

        - 使用频率最多的函数

        - 声明式和赋值式创建的函数

        ```js

            function 函数名(){}

            var 变量名 = function(){}

        ```

        - 执行

            - 常规执行:函数名或变量名()

    - 无名函数:

        - 非正常函数

        - 没有名字

        ```js

            function(){}

        ```

        - 不允许直接存在于代码空间中,否则会报错

        - 使用场景:

            1. *作为*变量的**值**存在(赋值式创建函数时的**值**)

                ```js

                    var 变量名 = function(){}

                ```

                - 执行:函数名|变量名()

            2. *作为*事件处理函数执行

                ```js

                btn.onclick = function(){

                    // 当事件被触发时要执行的内容...

                }

                ```

            3. ...

 

    - 匿名函数:

        ...

 

## 5.函数的参数

- 什么是参数

    - 根据用户传入不同的参数,选择执行函数中不同的功能

- 参数的分类:

    - 发:实参:函数执行时的参数

    - 收:形参:函数定义时的参数

    - 实参和形参的关系,赋值的关系,形参相当于变量,实参相当于值,一对一

 

- 数量对应关系

    - 参数可以有很多个,语法上没有数量限制,但是行业有习惯,自定义函数,如非特殊需要,尽量不要超过3个

    - 实参和形参数量一致:

        - 按照顺序,一一对应

    - 实参多:

        - 没有形参接收,通过形参找不到

        - 在函数内部有个神秘的空间(arguments),这个空间会将所有的实参全部保存,不论有没有被接收

        - arguments是个对象类型的数据(类数组的数据)

            - 长度(个数),表示接收到了几个实参

                - `arguments.length`

            - 索引(序号,编号),表示数组内部的数据位置,索引从0开始

                - `arguments[索引]`

    - 形参多:

        - 多出来的形参是undefined

        - 形参其实就是一个变量,实参是赋值,如果实参不够,表示没有赋值,undefined

## 6.函数的返回值

- 返回值概念

    - 函数自身的处理数据或执行结果,需要被二次使用或其他程序调用时,需要将数据返回出来

- 如何拿到返回值

    - 关键字:`return 要返回的数据`

- return的功能

    - 可以让函数返回指定的**值**

    - 可以立即结束当前函数

        - 一个函数中可以写无数个,但是只能执行一次return,一次只能返回一个数据,不允许返回多个数据

- 返回到哪

    - 返回到函数的执行语句

        - 函数名(),既是在执行函数,也是在拿返回值

- **注意**

    - 一个函数如果没有return,那么返回的是undefined;如果有return,那么返回值就是return后面的值

- 可以返回哪些数据

    - 所有数据

        - 当返回函数时,形成了闭包(后期概念)

- 什么时候需要返回值?

    - 功能性函数(打印表格,改颜色)

        - 可以有,但是没有必要有返回值

    - 处理数据的函数(补零,计算器,计算圆的面积)

        - 一般都有,返回数据

 

## 补充:事件分类

- 鼠标类

- 键盘类

- 表单类

举例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        #box{width: 100px;height: 100px;background: red}
    </style>
</head>
<body>
    <div id="box"></div>
    <input type="text" id="txt">
</body>
<script>
    // 人机交互
        // 输入和输出
            // 输入设备:鼠标,键盘,...
            // 输出设备:显示器,音响,...

    // 事件按照输入设备分:
        // 鼠标类:
            // 单击:click
            // 双击:dblclick
            // 按下:mousedown
            // 抬起:mouseup
            // 移动:mousemove
            // 进入:mouseover / mouseenter
            // 离开:mouseout / mouseleave
            // 右键:contextmenu

        // 键盘类:
            // 按下:keydown
            // 抬起:keyup
            // 按下并抬起:keypress

    // 网页的特色事件
        // 浏览器类:
            // 加载:load
            // 滚动:scroll
            // 改变大小:resize

        // 表单类:
            // 获取焦点:focus
            // 失去焦点:blur
            // 输入:input
            // 内容改变:change
            // 提交事件:submit
            // 重置事件:reset
    

    // 。。。。。。。。


    // 所有事件的绑定方式都是一致的
        // 目前学习了一种:on绑定,赋值式绑定
            // 元素.on事件名 = function(){}

    // 注意:行为的触发方式是否正确
            // 尤其是表单类

    // 喝水需要经过哪些行为?
        // 假设杯子里有水,放在手边
            // 伸手,找到杯子,抓住杯子,移动到嘴边,张嘴,抬手,喝

    // 在计算机上拖拽一个文件:
        // 按下,移动,抬起

    // 鼠标事件测试

    var box = document.getElementById("box");
    box.onclick = function(){
        console.log("单击事件发生了")
    }
    box.ondblclick = function(){
        console.log("双击事件发生了")
    }
    box.onmousedown = function(){
        console.log("按下事件发生了")
    }
    box.onmouseup = function(){
        console.log("抬起事件发生了")
    }
    box.onmouseover = function(){
        console.log("进入事件发生了")
    }
    box.onmouseout = function(){
        console.log("离开事件发生了")
    }
    box.onmousemove = function(){
        console.log("移动事件发生了")
    }
    box.oncontextmenu = function(){
        console.log("右键事件发生了");
    }

    // 表单事件测试

    var txt = document.getElementById("txt");
    txt.onfocus = function(){
        console.log("获取焦点事件")
    }
    txt.onblur = function(){
        console.log("失去焦点事件")
    }
    txt.oninput = function(){
        console.log("输入事件")
    }
    txt.onchange = function(){
        console.log("改变内容事件")
    }

# 二、作用域

- 谁作用的哪个区域

    - 谁:数据(变量)

    - 哪个:如何划分,函数就是一个区域

 

- 全局

    - 不属于任何一个函数

    - 全局作用域中的变量,叫全局变量

    - 全局作用域中的函数,叫全局函数

    - 生命周期:一直存在

    - 耗性能,但是方便

        - 少用全局

 

- 局部

    - 任何一个函数内部都是局部作用域

    - 局部作用域中的变量,叫局部变量

    - 局部作用域中的函数,叫局部函数

    - 生命周期:朝生暮死

    - 节省内存,不方便

 

    - 函数的参数(形参):是当前函数的局部变量

 

- 匿名函数

    - 利用匿名函数解决全局耗性能,局部不方便的问题

    - `(function(){})()`

 

# 三、变量的读写规则

- 当全局和局部的变量名重复时

- 读的规则:

    - 向上级作用域查找,找到了,就使用,同时,停止查找;找到顶级作用域,都没有,**报错**

 

- 写(设置,赋值)的规则:

    - 向上级作用域查找,找到了,就写入,同时,停止查找;找到顶级作用域,都没有,**会默认在顶级作用域声明这个变量,然后使用**

 

- 注意:声明变量时,必须加声明关键字,不加声明关键字,可能能执行,但是不规范

 

# 四、JS的编译和执行

- 偏原理

    - 可以不懂原理,只需要注意现象,可以正常写代码

    - 懂原理,帮助你提升代码性能,优化;方便面试

- js是一门解释性语言

    - 预先编译,再执行

    - 先通读全文,在解释含义

        - 找到var和function,做出对应提升

- 编译时

    - **提升**

- 执行时

    - 按照逻辑,结构正常执行

 

## 变量和函数会提升

- var的提升

    - 提前声明,=号的位置赋值

        ```js

        console.log(a);     // undefined

        var a = 10;

        console.log(a);     // 10

        ```

        - ↑↑↑↑等价于↓↓↓↓

        ```js

        var a;

        console.log(a);     // undefined

        a = 10;

        console.log(a);     // 10

        ```

- function的函数提升

    - 整体提升

    - 即提前声明,有提前赋值

- 如果var遇到function

    1. 赋值式创建函数       ********

        ```js

        var fn = fucntion(){}

        ```

        - 提升的是var,不是function

    2. 变量和函数重名

        ```js

        var a = "hello";

        function a(){}

        ```

        - var提升的更高,所以function占便宜,生效的是function

 五、函数的高级应用-递归

- 在函数内部执行自己

- 递归就是函数自己调用自己

- 递归类似于循环

- 递归函数要注意停止/返回,否则会造成死递归

- 递归比较消耗性能,尽量少用

举例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        
    </style>
</head>
<body>
    <div id="box"></div>
</body>
<script>

    // 在函数内部执行自己
    // 自己调用自己

    // function fn(){
    //     fn();
    // }
    // fn();

    // 以上代码会:死

    // 递归就像:一条蛇吞了自己的尾巴

    // 递归如果控制好结束条件,可以模拟循环,解决循环能解决的问题

    // 所以,直接递归虽然不好,但是可以利用递归的思想,解决一些实际需求

    // 递归的缺点:内存溢出,浪费大量的性能,占用过多的进程

    // 递归是一个逻辑算法的体现

    // 思想,不是浪费的性能

    // 看电影,去晚了,开场了,灯关了,很黑,啥都看不见,只能看见人

    // 递归:
        // 递:不断向内执行的过程
        // 归:不断向上返回的过程

        // 递归必须包含这两个过程,如果只有递没有归,那么程序未响应

        // 递就是在执行自身,自己调用自己
        // 归就是结束,或返回,返回值

    // -----------------电影院问作为的案例得出------------------
        // 每个座位号都是前一个座位号+1
        // 当前座位号 = 前一个座位号 + 1
        // 假设,计算当前座位的功能:fn,计算第n排
        // fn(n) = fn(n-1) + 1
        
        // 递:
        // fn(5) = fn(5-1) + 1
        // fn(4) = fn(4-1) + 1
        // fn(3) = fn(3-1) + 1
        // fn(2) = fn(2-1) + 1
        // fn(1) = fn(1-1) + 1
        // fn(0) = 0

        // 归:
        // fn(5) = 4 + 1
        // fn(4) = 3 + 1
        // fn(3) = 2 + 1
        // fn(2) = 1 + 1
        // fn(1) = 0 + 1
        // fn(0) = 0

    // 阶乘:5的阶乘------------其实就是当前数字~1的累乘
        // 5! = 5 * 4!
        // 4! = 4 * 3!
        // 3! = 3 * 2!
        // 2! = 2 * 1!
        // 1! = 1

        // 5! = 5 * 4 * 3 * 2 * 1
        // 4! = 4 * 3 * 2 * 1
        // 3! = 3 * 2 * 1
        // 2! = 2 * 1
        // 1! = 1
    
        // 假设,计算阶乘的功能:fn,计算n的阶乘:fn(n)
        // 当前数字的阶乘 = 当前数字 * 前一个数字的阶乘
        // fn(n) = n * fn(n-1);

        // n = 1;
        // fn(n) = 1;

        // function fn(a){
        //     if(a === 1){
        //         return 1;
        //     }else{
        //         return a * fn(a-1);
        //     }
        // }
        // console.log(fn(10));


        // --------计算当前数字~1的累加---------

        // function fn(a){
        //     if(a === 1){
        //         return 1;
        //     }else{
        //         return a + fn(a-1);
        //     }
        // }
        // console.log(fn(10));

        // ----------斐波那契数列----------
        // 1,1,2,3,5,8,13,21,34,55......
        // 规律:从第三位开始:当前数字 = 前一个数字 + 再前一个数字
        // 假设一个计算当前数字的功能:fn,如果向计算第n个数字
        // fn(n) = fn(n-1) + fn(n-2);

        // 实现假设

        function fn(n){
            if(n === 1 || n === 2){
                return 1;
            }else{
                return fn(n-1) + fn(n-2);
            }
        }
        console.log(fn(10));

        
        // 找不到规律,适合用递归么

        



</script>
</html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值