JS 函数

98 阅读4分钟

不知不觉已经到了JS中的 函数

那么 函数是什么呢 划重点 可不是数学中的函数噢

你可以初步先把 函数 想成一个盒子 div 为什么要有函数呢 它的作用是什么

帮我们把项目中多个地方使用到的功能(代码段)抽离出来(把它放到这个“盒子”里, 就不需要在多个地方书写重复的功能)

然后在需要的地方 调用函数 即可

写一个完整的函数分为两部分

1.定义阶段

2.调用阶段

函数的定义

语法:

function ( ) { }

两种定义函数的方式

  1. 赋值式定义

var fn = function ( ) { }

  1. 声明式定义

function 函数名( ) { }

例:
赋值式定义:
    var fn = function () {}
    console.log(fn)
    
声明式定义:
    function fn1() {}
    console.log(fn1)
    

函数的调用

不管函数定义是如何定义的, 调用方式永远只有一种

语法:

 赋值式定义
 var fn = function () {
     console.log(111)
} 
 fn()
 

赋值式定义没有函数名, 但是存储在变量 fn 中, 所以我们可以把 fn 理解为当前这段函数的函数名

声明式定义
fn()
function fn1() {
    console.log(1)
}
fn1()

函数定义声明式和赋值式的区别

  1. 书写不同
  2. 打印时, 声明式会带上函数名, 赋值式没有
  3. 调用时有差异

声明式定义可以在函数定义前调用,赋值式不可以

    例:
    fn1()            // 111
    function fn1() {
        console.log(111)
    }
    fn1()            // 111

    fn()             // fn is not a function
    var fn = function () {
        console.log(222)
    }
    fn()             // 222
    

函数的参数

函数的参数是什么?

我们的函数在不写参数的时候, 可以正常执行

但是! 函数的功能相对单一

如果函数想要真正的灵活起来, 在多个地方调用时 有不同的执行, 那么我们可以通过函数的参数来完成

参数分为两个:

形参:

函数名后(function) 后边的小括号内部, 每书写一个 就相当于在函数内部声明一个变量, 可以在函数内部去调用

实参:

调用函数时的小括号内部书写的值, 就是实参, 实参与形参为 一一对应的关系(例1)

形参与实参会一一对应 如果实参数量少于形参 那么前边的形参对应接受值 没有对应实参的形参值为undefined(例2)

如果形参数量 少于 实参 那么会一一对应后, 多余的实参无法通过参数获取 (例3)

1.png

函数的返回值

**语法: **

return 需要返回的内容 

但是在每一段的函数里 返回值一定需要吗?什么时候需要写返回值?

返回值的书写取决于是否需要得到函数内部某一个变量的值, 如果需要,可以使用返回值将其返回, 如果不需要我们可以不写使用函数的默认返回值

注意:

函数有默认返回值

我们可以不写 return返回值 函数会默认在代码段最后一行 写上 return undefined

例:
function fn() {
console.log(1)
}
var sum = fn()  

console.log(sum)    // undefined

console.log 控制台最终打印: 1 underfined

return 具有中断函数执行的功能

如果不想中断函数, 那么一定要将 return 放在函数的最后

除非就是想要通过 return 中断函数的运行

 例:
 function fn() {
        console.log(1)
        return
        console.log(2)
        console.log(3)
        console.log(4)
        console.log(5)
    }
    fn()     //控制台显示1 后面不执行
    
    

函数的预解析

我们的JS引擎在运行的时候是分为两步的

  1. 预解析

  2. 运行代码

预解析之后(会把函数提升到当前作用域最顶层)

注:

在 JS 中 只有变量和函数才会有预解析或者说提升

(1)变量提升 就是把所有的变量声明提升到当前作用域的最顶层 但不提升赋值操作

(2)函数提升 就是把所有函数声明提升到当前作用域的最顶层 函数调用不提升(函数的预解析, 可能会遇上同名变量的变量提升(变量的预解析) 以函数为主)

2.png

所以这也就解释了 为什么赋值式函数在函数之前调用会报错 是因为 "预解析"

递归函数

程序调用自身的编程技巧称为递归( recursion)递归作为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法

在函数内部, 调用自身 此时就是写了一个递归函数

但是我们在学循环的时候 是有死循环的 那 有死递归吗? 回答是:

死循环版本:
  function fn() {
      fn()
  }
 fn()

要想写一个正确的递归函数, 需要在递归内部, 写上返回点(到某个条件时, 停止递归)

举例:我们要 求一个数字的阶乘

求4的阶乘 (4x3x2x1)

 function fn(n) {
// 1. 先写折返点, 到某个条件停止递归
if (n == 1) return 1

// 2. 不符合结束递归时运行的代码
 return n * fn(n - 1)
}
 var sum = fn(4)
 console.log(sum)    // 24