函数, 分支结构

157 阅读7分钟

1. 函数

  • 什么是: 内存中封装一项任务步骤清单的代码段, 再起一个名字

  • 为什么: 代码重用

  • 没有函数的弊端:

    • 事件中想执行 JS 脚本只能逐行编写
    • 可重用性不高
  • 何时: 只要一段代码, 可能被反复使用, 都要先封装在函数中, 再反复调用函数

  • 如何: 2 步

    1. 声明:

      function 函数名(参数列表){
        函数体;
        return 返回值;
      }
      
      • 参数: 函数运行时, 接收传入函数的数据的变量, 只不过不用 var 创建
      • 参数列表:
        • 多个参数间用逗号分隔
        • 何时: 当一项任务必须某些数据才能正常执行时
        • 为什么: 参数可让函数变得更灵活
      • 返回值: 函数执行的结果
        • 何时: 如果函数的调用者需要获得函数执行结果
        • 如何返回: return 返回值
          • 其实, return 可单独使用 -> 退出函数
          • 如果没有返回值的函数, 其实也返回东西 -> 默认返回 undefined
    2. 调用: 让引擎按照函数的步骤清单, 执行任务

      • 在任意合法的 JS 脚本位置处都可以调用函数
      • 语法: 函数名(参数值列表)
        • 参数值列表: 传入函数的执行时必须的数据列表
          • 只要函数定义时规定了参数变量, 调用时传入的顺序必须保持一致

          • 每个参数值之间用逗号分隔

      强调: 函数不调用不执行, 只有调用才执行

    3. 特殊情况

      • 如果一个表达式或函数有结果, 就可直接当一个值用

      • 如果传入参数个数不符, 不会报错

        • 个数超了, 多出的没用; 个数不够, 未接到值的参数变量, 默认值 undefined
      • 在函数内, 为没有声明过的变量赋值, 变量会被自动创建在全局 -> 危险

        • 强烈建议: 所有变量使用前, 必须先声明

      • return 特点: return 不能放在其他表达式中间使用

    4. 函数和方法: 都是 function 对象, 函数和方法本质是一样的

      • 函数: 不属于任何对象的叫函数( 不需要通过 . 访问 )
      • 方法: 属于特定对象的函数叫方法( 需要通过 对象**.** 才可访问 )

2. 作用域

  • scope : 一个变量的可用范围, 包括: 2 种

  1. 全局作用域: window
    • 全局变量: 直接定义在全局中, 不属于任何函数的变量
    • 特点: 可反复使用, 随处可用
    • 何时: 如果一个变量需要反复使用, 或跨函数随处可用时
  2. 函数作用域:
    • 局部变量: 2 种
      1. 函数的参数变量
      2. 在函数内 var 出的变量
    • 特点: 仅在函数内可用, 出了函数不能使用
      • 不可重用
    • 何时: 如果一个变量, 仅希望在函数内有效时
  3. 总结: 1. 优先定义并使用局部变量 2. 尽量少使用全局变量 -> 避免被污染
  4. 变量的使用顺序: 1. 优先使用函数内的局部变量 2. 只要局部声明了, 就不用全局的 3. 除非局部没有声明, 才去全局找

3. 声明提前( hoist )

  1. 什么是:

    在开始执行程序前, 引擎会将 var 声明的变量和 function声明的函数, 提前到当前作用域顶部集中优先创建 -> 再开始执行程序, 赋值留在原地

    • 鄙视: 如果先使用, 后声明, 一定在考声明提前
      • 就要将所有 varfunction 提前到当前作用域的顶部, 先创建, 再判断程序的输出
  2. 解决: 变量

    • 传统: 强烈建议将所有的声明都集中在当前作用域顶部
    • ES6+: let 代替 var 声明变量
      • let 要求: 在 let 之前, 不允许提前使用该变量
  3. 函数: var 函数名=function(...){...}

    • 本质: 函数名其实仅是一个普通的变量
      • 函数其实是保存代码段的引用类型的对象
      • 函数名通过函数对象的地址引用着函数对象

4. 按值传递

  • 什么是:

    两变量间赋值, 或向函数中传入参数时, 其实只是将原变量中的值复制一个副本给对方

  • 结果:

    • 原始类型的值: 修改新变量, 不影响原变量的值
    • 引用对象的值: 按值传递, 将变量中的地址复制给对方

5. 全局函数

  • 什么是: ES 标准中规定的, 不需要任何对象就可直接调用的函数
    • Ex: String() / Number() / Boolean() / parseInt() / parseFloat() / isNaN()
    • 反例: alert() / prompt()

6. 编码解码

  • 什么是: 将 url 中多字节字符或保留字符编码为单字节

  • 为什么: url 中不允许出现多字节字符以及和保留字符冲突的字符

  • 何时: 只要 url 中包含多字节字符以及和保留字冲突的字符时, 都要先编码为单字节

  • 如何: 1. 编码: var code = encodeURI( url )

    1. 解码: var text = decodeURI( url )
  • 问题: 不能对保留字符编码解码, Ex: ``:,/`

    • 冒号在 url 中区分协议名和主机名, 而斜杠用来表示路径上下级的区分
    • 解决: 1. 编码: var code = encodeURIComponent( url ) 2. 解码: var text = decodeURIComponent( url )

7. eval 函数

  • 专门执行一段字符串格式的 JS 表达式, 还可计算字符串格式的表达式的值

  • 普通模式下, eval 中代码的作用域就是 eval 所在的作用域, 在严格模式下, eval 自己一个作用域, eval 中声明的变量或函数在 eval 外不能用

  • Ex: console.log(eval('4+7')) -> 11

8. 分支结构

  • 程序三大结构: 顺序, 分支, 循环

    • 顺序: 除去声明提前, 其余代码默认都从上向下顺序执行
    • 分支: 根据不同的条件, 执行不同的代码操作
    • 循环: 让程序反复执行一段相同代码
  • 程序 = 数据结构 + 算法

  • 什么是: 让程序根据不同的条件执行不同的操作

  • 何时: 只要让程序根据不同的条件执行不同的操作

  • 如何:

    1. 一个条件, 一件事, 只有满足才做, 不满足就不做

      • 如果操作简单: 利用短路逻辑 -> 条件 && ( 操作1, 操作2...)

        • 操作可以用分号隔开写多个
      • 如果操作复杂: if(条件){操作代码段}

        • 满足条件就执行操作

        • 条件可以是任意关系运算或逻辑运算, 只要返回 truefalse 的函数或表达式, 都可当条件用

    2. 一个条件, 二件事, 二选一执行 -> 满足条件做第一件, 不满足做另一件

      • 如果仅两个值二选一: 条件 ? 值1 : 值2
      • 如果操作简单: 三目 / 三元 / 条件: 条件 ? 操作1 : 操作2
      • 如果操作复杂: if (条件) { 操作1 } else { 操作2 }
    3. 多个条件, 多件事, 多选一执行

      • 如果多个值, 多选一: 三目

        • 条件1 ? 值1 : ( 条件2 
          	?  值2 : 值3 )
          
        • 强调: 默认值不能省略

      • 如果操作简单: 三目

        条件1 ? 操作1 : ( 条件2 
        	?  操作2 : 操作3 )
        
      • 如果操作复杂: if...else if结构

        if(条件1){
        	操作1 //如果当前条件满足,则不再向后执行
        }else if(条件2){
        	//如果进入条件2,暗示条件1不满足
        	操作2
        }else if(...){
        	...
        }else{ // 如果没有默认操作,则else省略
        	默认操作
        }
        
        • 简写: 如果 if/else if/else 下只有一句话, 可省略 {}
    4. 特殊:

      • 如果所有条件都是等于比较, 可简写为

        switch(表达式){  //先计算表达式的值
        	//用表达式的值和每个case后的值做*全等*比较
            case1:  //如果表达式的值全等于case后的值
        		操作1;  //就进入case下执行操作
            	break;
        	case2:
        		操作2;
            	break;
               ...
        	default:  //如果所有case的值都不等于表达式的值
        		默认操作;  //则执行默认操作
            	break;
        }
        
        • 强调: 最后一个default可省略