第一篇 JS 语言基础之函数

218 阅读7分钟

1.4.2.4 函数 function

1. 函数概念

  1. 什么是函数?

函数就是一个方法或者一个功能体

封装: 函数就是把实现某个功能的代码放到一起进行封装(不执行)

封装: 低耦合高内聚

       减少页面中的冗余代码,提高代码重复使用率

调用: 想要操作实现这个功能只需调用执行函数 (函数不能自然而然的执行,需要调用才能执行)

理解

洗衣机就是一个函数,生成洗衣机就是封装一个函数(把实现功能的代码封装进去)

生产的时候不知道用户放什么水 衣服 洗衣剂,我们需要提供出入口

提供的入口叫做形参

执行的时候放入的具体东西叫做实参

出口在函数中叫返回值,把函数处理后的结果能够返回给外面用

  1. 学习函数要点
  • 创建函数

    • 形参

    • 返回值

  • 执行函数

    • 实参
  • arguments

  • 函数底层运行机制

  • ...

2. 函数基础语法与形参

2.1 函数基础语法

  1. 语法
    <script>
    // =================ES5 老方式============
        // 创建函数
        function [函数名]([形参变量 1], ...){
            // 函数体 基于 JS 完成需要实现的功能
            return [处理后的结果];
        }
        // 执行函数
        [函数名]([实参 1], ...);
    </script>

  1. 应用例
  • 求两个数的和,算完和以后乘以 10,然后除以 2...
    <script>
        // sum 是函数名,代表这个函数
        // sum()是让函数执行,代表函数执行返回的结果
        // n m 是形参,是变量,用来存储执行函数时传递的实参
        function sum(n, m) {
            let result = n + m;
            result *= 10;
            result /= 2;
            console.log(result);
        }
        console.log(sum); // sum 代表函数本身
        // 10 20 25 都是传递给形参变量的值
        sum(10, 20);
        sum(25, 20);

    </script>

2.2 形参的细节

  1. 创建函数的时候我们设置了形参变量 , 但如果执行的时候并没有传递对应的实参值,那形参变量默认的值是 undefined
 <script>
        function sum(n, m) {
            console.log(n , m); // 见'控制台打印结果 图 1'
            let result = n + m;
            result *= 10;
            result /= 2;
            console.log(result); // 见图 2
        }
        sum(); 
        sum(10); 
        sum(10,20); 
        sum(10,20,30); 

    </script>

控制台打印结果 图 1

image.png

图 2

image.png

  1. 形参默认值处理 : 不想要 undefined 作为默认值,如果没有给予实参值,给予一个默认值
    <script>
        function sum(n, m) {
            // 形参默认值处理 两种方法
            if(n === undefined){
                // 必须要用 === 
                // 如果用 == , null == undefined 为 true
                n = 0 ;
            }
            if(typeof m === 'undefined'){
                // 也可以用 == 
                m = 0 ;
            }
            console.log(n , m);
            let result = n + m;
            result *= 10;
            result /= 2;
            console.log(result);
        }
        sum(); 
        sum(10);
        sum(10,20);
        sum(10,20,30);

    </script>

3. 函数的返回值

背景介绍

   <script>
        function sum(n, m) {
            let result = n + m;
            console.log(result); // => 30
        }
        sum(10,20);
        console.log(result); // 报错 引用错误 见图 3
    </script>

图 3

image.png

函数执行的时候,函数体内部创建的变量我们在外部无法获取和操作的(闭包 作用域)(所以报错)

  1. 如果想要获取内部的信息,我们需要基于 return 返回值机制,把信息返回才能拿到
    <script>
        function sum(n, m) {
            let result = n + m;
            // 2.return 一定是值,此处把 result 变量存储的值返回给外面
            return result // => return 30
        }
        sum(10,20);
        let AA = sum(10,20);
        console.log(AA);// => 30
        console.log(result); // 报错 引用错误,见图 3 
    </script>
</body>

  1. return 的一定是值: 此处是把 result 变量存储的值返回给外面 不是变量(代码见上)

    函数名() 代表函数返回的结果,用来接 return 的东西

    retunr 与 函数名() 搭配使用

    对比 形参用来接实参,参与计算处理

    return 用来把函数执行结果给外面

  2. 没有写 return,函数默认返回值的 undefined(代码见下)写了return没有给值,返回undefined

    <script>
        function sum(n, m) {
            let result = n + m;
        }
        let AA = sum(10,20);
        console.log(AA); // => undefined
    </script>

注意:

image.png

1.console.log是函数

2.console.log(1) 是函数执行

3.undefined 是因为函数没有 return

4.1能打印出来是因为函数的功能

  1. 不需要返回值,但是仍旧写了 return,因为函数体中遇到 return,后面代码则不再执行了(代码见下)
    <script>
        function sum(n, m) {
            //函数体中遇到 return,后面代码则不再执行了
            if(n === undefined || m === undefined){
                return
            }
            let result = n + m;
        }
        sum(10,20);
    </script>

复习:

一个知识点,另一个知识点,几句话将两个知识点关联起来且不牵强

continue break return

4. 匿名函数

ES5 规范里的函数 : 匿名函数

  1. 什么是匿名函数 ? 没有函数名的函数

  2. 两种写法

  • 匿名函数之函数表达式,把一个匿名函数本身作为值赋值给其他东西

这种函数一般不是手动触发执行(函数名()),而是靠其他程序驱动触发执行(例如 : 触发其他事件的时候 把它执行)

    <script>
        document.body.onclick = function(){}
        setTimeout(function(){},1000);
        let fun = function(){};
    </script>

  • 匿名函数之自执行函数 : 创建完一个匿名函数,紧接着就把当前函数加小括号执行
    (function(n){
        // n => 100
    })(100);

小试牛刀 项目四 选项卡案例

5.首次了解函数的底层运行机制

执行下列代码

        // 创建函数
        function fn(n,m) {
            var res =null ;
            res = n + m;
            return res;
        }
        // 执行函数
        var AA = fn(10,20);
        console.log(AA);
  1. 创建函数,开辟的堆内存中存储的是函数题中的代码,但是是按照字符串的格式存储的.仅此而已.

    • 函数名代表函数

    • 函数名() 代表函数返回值 return右侧的内容

      • 类与实例 返回值return有不同情况
  2. 执行函数,先执行函数,再把返回值和变量(AA = fn())相关联.

    函数的返回值只看return 后面时啥就返回啥,没有就是UNDEFINDE.

  3. 每次执行函数的目的,都是把函数体中的代码(先从字符串变为代码)执行

    形成一个全新的私有栈内存(私有上下文)

  4. 执行时,在私有栈内存中进行变量存储和值存储,并关联,然后运算.

  5. res只能在上述私有栈内存中使用,如果想要在外界拿到,需要return返回给外面.

  6. 每次执行函数都会开辟一个私有栈内存(每次执行都另开一个),容易造成栈溢出,由此引出执行销毁的问题.JS的编译过程VO AO ...

image.png

练一练 项目6 对自定义属性的理解

... 未完待续

6. 函数中的ARGUMENTS (任意数求和应用)

思考: 任意数求和如何实现 ? (执行函数的时候 , 传递 N 个值求和)

 任意数求和:
            1. 传递实参的个数不定
            2. 传递的值是否为有效数字不定
            要求: 把传递的有效数字进行相加求和

            问题: 无法确定要传多少个行参接实参, 进而也无法进行挨个相加求和

6.1 arguments 是函数内置的实参集合

1. 类数组集合,集合中存储着所有函数执行时,传递的实参信息
               
2. 内置: 无论是否设置行参,argumwnts仍存在
                
3. 内置: 无论是否传递实参,argumwnts仍存在,只不过是一个空的类数组
                 
      - 空表现为argumwnts的length属性值为0
            
4. arguments.callee : arguments的 callee属性, 存储的是当前函数本身
                
      - 一般不使用,JS严格模式下禁止使用这个属性

6.2 任意数求和

  1. 使用for循环
未处理非有效数字
       function sum() {
           let total = null;
           for (let i = 0; i < arguments.length; i++) {
               let item = arguments[i];
               total += item ; 
           }
           return total
       }
       let total = sum(10,20,30,40) // => 100
       total = sum(10,20) // => 30
       total = sum(10,20,'30') // => '3030'
       total = sum(10,'AA') // => '10AA'

       function sum() {
           let total = null;
           for (let i = 0; i < arguments.length; i++) {
               // 获取的每一项结果都先转换为数字(数学运算)
               let item = Number(arguments[i]);
               // 非有效数字不加
               if(isNaN(item)){
                   continue;
               }
               total += item ; 
           }
           return total
       }
       let total = sum(10,20,30,40) // => 100
       total = sum(10,20) // => 30
       total = sum(10,20,'30') // => 60
       total = sum(10,'AA') // => 10

7. 箭头函数 ARROW FUNCTION (ES6+)

(this部分会详细补充)

7.1 箭头函数改写

  1. 语法:

    let 函数名 = ( 形参 ) => { 函数体 } ;

    如果函数体中只有一行 return的代码 , 可以省略return以及大括号 .

    let 函数名 = ( 形参 ) => 函数体 ;

    多行不可以 .

    <script>
   function sum(n,m){
       return n + m;
   }

   // 改成箭头函数
   let sum = (n,m) => {
       return n + m;
   }

   let sum1 = (n,m) => n + m;
   </script>

  1. 箭头函数在高阶函数的应用(柯里化函数)
        function fn(n) {
            return function (m) {
                return n + m;
            }
        }
        
        // 改写
        let fn = n => m => n + m;

第一步 改写最外侧的函数fn拿到箭头

image.png

第二步 改写小函数变为箭头

image.png

第三步 简化最里面的return 一行

image.png

第四步 简化剩余的return 一行

image.png

7.2 箭头函数的优点

  1. 写法简化

  2. 形参赋值默认值

    当没有给形参传递实参的时候,执行默认值

    这种写法也可以在非箭头函数中使用 ,但是更常用于ES6箭头函数中

        function sum(n, m) {
            if (typeof n === 'undefined') {
                n = 0
            }
            return n + m;
        }
    
        // 改写成箭头函数
    
        let sum = (n = 0, m = 0) => n + m;
    
  3. 箭头函数没有ARGUMENTS

  4. 箭头函数中的THIS也稍有不同

7.3 箭头函数没有ARGUMENTS

        let sum = () =>{
            console.log(arguments); // => arguments is not defined
        }
        sum(1,2,3,4)

使用扩展运算符... 来获取预算福获取到传递的实参集合

  • 该实参集合数据类型是数组

其中arg是自定义参数,可以随意写

        let sum = (...arg) =>{
            console.log(arg); // => [1,2,3,4]
        }
        sum(1,2,3,4)

想要实现任意数求和功能

        let sum = (...arg) =>{
            return eval(arg.join('+'))
        }
        sum(1,2,3,4)
        
        ====================
        另外一种写法
        
        let sum = (...arg) => eval(arg.join('+'))
        
        sum(1,2,3,4)


eval() 的参数是一个字符串。如果字符串表示的是表达式,eval() 会对表达式进行求值。如果参数表示一个或多个 JavaScript 语句,那么eval() 就会执行这些语句。

7.4 箭头函数中的THIS与普通函数也不同

...待补充