函数

5,380 阅读6分钟

函数的概念

  • 什么是函数?
    • 首先明确一点,和我们数学中的函数是两个概念
    • 在 JS 中,函数可以理解为将一段在程序中多次出现的代码封装起来的盒子,以便在多个地方调用执行
    • 换句话说:函数就是一个内部封装了部分代码的盒子,可以在多个位置被调用
  • 函数的使用
    • 创建函数(定义函数)
    • 调用函数

函数的定义

  • 声明式定义
function fn() {
    
}
/**
 * 分析:
 *      function:声明函数的关键字,代表接下来这段代码是一个函数
 *      fn:函数名,调用函数时需要使用,函数名自定义,符合命名规范和见名知意即可(!** 匿名函数时可以不写)
 *      ():小括号内存放函数的参数(后续讲解)
 *      {}:存放函数代码,调用函数时,想执行的代码都写在内部
*/
  • 赋值式定义
var fn = function () {

}
  • 两者区别
    • 1.写法不同; 2.调用上略有不同,声明式可以在定义前调用,赋值式只能在定义后调用
      • 赋值式定义函数不能再函数定义前调用的原因:
        • 赋值式定义, 其实就是声明一个变量, 然后给他赋值为一个函数;
        • 在js里,定义变量之前 使用变量时,变量的值为undefined---变量提升

函数的调用

function fn1() {
    
}
var fn2 = function () {

}

fn1()
fn2()

声明式与赋值式的区别

  • 书写区别
  • 调用区别
// 声明式
fn1()  // 可以执行
function fn1(){
    // 函数代码。。。。。。
}
fn1()  // 可以执行


fn2()   // 不可以执行(!**  声明时编程,其实就是相当于将一个函数赋值给一个变量,会有变量的声明提升,所以在变量声明前调用时,根据变量声明提升的规则,此时变量为 undefined ,所以不能被调用)
var fn2 = function () {
    // 函数代码。。。。。。。。。
}
fn2()   // 可以执行

函数的参数

  • 参数是什么?
    • 如果没有参数,那么函数的执行功能是固定的,写好函数后内部内容将不会变
    • 比如:函数内部的代码为 1 + 1,那么始终执行时始终都是 1 + 1,如果此时想要计算 1 + 2 的值,需要重新封装一个 1+2 的函数
  • 参数在哪里?如何使用
    • 书写函数时有一个 () 内部就是书写参数的,函数分为两种,形参---实参
  • 形参和实参的区别
    • 形参:在函数声明时 function 后边的()内书写,每写一个参数,就相当于在函数内部创建一个变量,其值为函数调用时传递的值,只能在函数内部使用,不能在外部使用
    • 实参:顾名思义,实际的参数,也就是函数在调用时传递的参数
function num () {
    console.log(1 + 1)
}
num()   // 打印值为 1+1

function num (a, b) {   // 此处 a b 为形参
    console.log(a + b)
}
num(1, 1)   // 此处为 实参,分别传递给 a  和  b
num(1, 2)   // 此处打印值为 1 + 2
  • 注意
    • 函数的形参与实参是按照从左到右的顺序一一对应的
      • 形参>实参,会将实参一一对应传递给形参,多出来的形参,相当于只定义,没赋值,值为undefined
      • 形参<实参,会将实参一一对应传递给形参,多出来的实参,无法在函数内部通过参数的方式调出
// 少传参数
function num1(a, b, c, d) {
    console.log(a,b,c,d)
}
num1(1, 2, 3, 4)    // 打印1,2,3,4
num1(1, 2, 4) // 打印1,2,4,undefined
num1(4) // 打印4,undefined,undefined,undefined
// 多传参数
function num2 (a) {
    console.log(a)
}
num2(1, 2)  // 打印 1
num2(1)  // 打印 1
  • 参数默认值
    • 函数在创建形参的时候,默认给一个值,将来在调用的时候,就算没有实参,无法传递,那么这个形参的值不会时undefined,而是默认值

函数的返回值

  • 返回值是什么?有什么作用
    • 函数内部默认有一个 return 他的值就是函数的返回值,如果函数内部不写 return 那么函数默认在函数体内部最底部返回一个 undefined
    • 如果不想返回 undefined 需要手动在函数内部写上 return 并且跟上需要返回的值
    • 可以中断函数(后续通过代码演示)
function num (a, b) {
    a+b
}
var ab = num(1,2)
console.log(ab)
function num (a, b) {
    // return a + b
    console.log('函数内部执行的 a + b =',a+b)
}
var ab = num(1,2)
console.log('函数外部执行的 a + b =',ab)
  • 需求:封装一个函数,判断一个数字是否为水仙花数,是的话,true,否则false(封装函数,需要参数吗,需要几个参数,需要返回值吗)
    function fn(a) {
      if (parseInt(a / 100) * parseInt(a / 100) * parseInt(a / 100) + parseInt(a / 10 % 10) * parseInt(a / 10 % 10) * parseInt(a / 10 % 10) + (a % 10) * (a % 10) * (a % 10) === a) { return true 
      }
      else { return false 
      }
    }
    var boo = fn(371)
    console.log(boo)

函数的优点

  • 函数其实就是将一段需要多次调用的代码抽离出来封装到一个盒子内部,方便在多个地方调用时简单化代码
    • 抽离公共代码,项目代码整体更加简洁
    • 方便(复用),在需要的地方直接 函数名 + 小括号 调用即可

函数的预解析

  • 什么是预解析
    • 在代码运行前,先全部分析一遍代码,这个行为叫做预解析(预解释)
  • 预解析的内容
    • 声明式函数在定义前可以被调用
    • JS在执行代码时,会有一个 解析阶段,在此阶段----函数提升------将声明式函数的定义,提升到 当前作用域的最顶端(暂时理解 当前页面最开始的位置)
// 正常书写代码
fn()
console.log(a)

function fn() {
    console.log(100)
}
var a = 100

// 预解析后可以理解为
function fn() {
    console.log(100)
}
var a

fn()
console.log(a)

a = 100

作用域

  • 作用域含义
    • 变量可以起作用的范围
  • 作用域分类
    • a.全局作用域(直接写在script内先的代码)
      • 在此作用域创建 的变量----全局变量,在script标签的哪里都能使用
      • 在JS中,全局作用域中有一个提前给我们准备好的对象----一种数据格式,这个对象叫window
      • 创建的全局变量,会自动添加到window对象中
    • b.局部作用域(JS里,只有函数里能创建局部作用域)
      • 在此作用域创建 的变量,只能在当前作用域使用,超出这个作用域(也就是在函数外部)去使用,就找不到变量
  • 作用域链(纯概念 面试)
    • 访问一个变量时,如果当前作用域内没有,会去自己的父级作用域(也就是上一层作用域内查找),找到就直接使用,如果没有,继续向上层查找,直到查到最顶层的全局作用域,找到了直接用,没有找到,报错提示变量不存在-----一层一层往上找的规律就是作用域链
    • 赋值规则
      • 给变量赋值,首先当前作用域内,有就赋值,并停止查找;没有就找父级,有就修改值,并停止找,没有就继续父级,直到全局作用域,找到就赋值,找不到就在全局创建一个变量,并赋值

递归函数

  • 本质还是函数; 当一个函数在函数内部,调用自身,就是递归(有点小缺陷)
  • 求阶乘100!
 function fn(n) {
      if (n === 1) {
        return 1
      }
      return n * fn(n - 1)
    }
    var sum = fn(100)
    console.log(sum)