函数的认识

认识函数

+ 函数是一个 js 的数据类型, 叫做 Function

+ 是一个复杂数据类型(地址/引用)

+ 私人: 就是一个 "盒子", 这个 "盒子" 可以承载一段代码

+ 涉及到两个过程

=> 函数定义阶段: 把代码装进盒子的过程

=> 函数调用阶段: 把盒子内的代码执行的过程

 函数的设计函数:需要站在用户调用者的角度去思考

    1.功能

    2.是否需要参数

    3.是否需要返回值

函数定义阶段

+ 就是一个把代码装进 "盒子" 的过程

+ 在这个过程中, 被装进去的代码是不会执行的

+ 方式1: 声明式函数

=> 语法: function 函数名() { 你要装进盒子的代码 }

-> function 定义函数的关键字

-> 函数名 你给这个盒子起的一个名字, 遵守变量命名规则和规范

-> () 书写参数的位置, 欠着

-> {} 代码段, 你要装进盒子的代码

+ 方式2: 赋值式函数(函数表达式), 就是把函数当做一个表达式赋值给另外的内容

=> 语法: var fn = function () {}

函数的嵌套调用:

                        一个函数在定义时,函数体内调用了其他的函数

主调函数 f1

    被调函数 f2

    function f1() {

        f2();

        console.log("f1");

    }



    function f2() {

        f3();

        console.log("f2");

    }



    function f3() {

        f4();

        console.log("f3");

    }



    function f4() {

        f5();

        console.log("f4");

    }



    function f5() {

        console.log("f5");

    }



    f1();

函数调用阶段

+ 两种定义函数的方式, 他们的 调用方式 是一样的

=> 语法: 函数名()

-> 函数名 表示你需要哪一个函数内的代码执行

-> () 把函数内的代码执行一遍, 

+ 两种定义函数的方式, 他们的 调用时机 是不一样的

=> 声明式函数可以先调用也可以后调用

=> 赋值式函数(函数表达式) 只能后调用, 先调用会报错

   

// 声明式定义函数

// 声明了一个叫做 fn 的函数

// function fn() {

// console.log('你好 世界')

// }

// console.log(fn)

// // 赋值式定义函数

// var fn2 = function () {

// console.log('hello world')

// }

// console.log(fn2)
 

函数的调用阶段

// fn()

// fn2()

// 函数调用的时机问题

// 在函数声明以前调用

fn()

function fn() { console.log('我是一个声明式函数') }

// 在函数声明以后调用

fn()

// 在函数声明以前调用, 直接报错

// fn2() // fn2 is not a function

var fn2 = function () { console.log('我是一个赋值式函数') }

// 在函数声明以后调用

fn2()

                                   函数的参数

函数的参数

+ 在函数内, 参数有两种

+ 形参

=> 书写在函数定义阶段的 () 内

=> 就是一个只能在函数内部使用的变量

=> 可以书写多个, 书写多个的时候中间使用 逗号(,) 分隔

=> 形参的值有函数调用时传递的实参决定

+ 实参

=> 书写在函数调用阶段的 () 内

=> 就是按照顺序依次给形参进行赋值的数据

=> 可以书写多个, 书写多个的时候中间使用 逗号(,) 分隔

函数的参数默认值

+ 给函数的形参添加一个默认值

+ 当你没有传递实参的时候, 可以使用默认值

+ 语法: 直接给形参进行赋值即可

例如

// function fn(a, b) {

// // 相当于在函数 fn 内定义了两个变量

// // a 和 b, 只不过现在没有赋值

// console.log('a : ', a)

// console.log('b : ', b)

// }
 

// // 本次调用没有传递实参, 没有数据给形参 a 和 b 赋值

// // 本次调用 a 是 undefined, b 是 undefined

// fn()

// // 本次调用只传递了一个实参

// // 10 被赋值给了 a 形参

// // b 依旧是 undefined

// fn(10)

// // 本次调用传递了两个实参

// // 按照顺序, 100 被赋值给了 a, 200 被赋值给了 b

// fn(100, 200)
 

// 函数的参数默认值

function fn(a = 100, b = 200) {

console.log('a : ', a)

console.log('b : ', b)

}

// 本次调用没有传递实参, a 和 b 形参都使用默认值

fn()

// 本次调用传递了一个实参给到 a, 那么 a 就是被赋值为 1, b 依旧是用默认值

fn(1)

// 本次调用传递了两个实参分别给到 a 和 b 了

fn(10, 20)

                                        案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <script>
    /*
      案例1: 求任意两个数字的和, 把结果显示在控制台
    */

    // function fn1(a, b) {
    //   // a 和 b 就是要求和的两个数字
    //   // 1. 求和
    //   var res = a + b

    //   // 2. 输出
    //   console.log(res)
    // }

    // // 将来想求 10 和 20 的和
    // fn1(10, 20)


    /*
      案例2: 求任意三个数字的和, 把结果显示在控制台
    */
    //  function fn2(a, b, c) {
    //    var res = a + b + c
    //    console.log(res)
    //  }

    //  fn2(10, 20, 30)

    /*
      案例3: 求任意个数字的和, 把结果显示在控制台
        + 当可变的内容数量不可控的时候
        + 我们的参数不好决定了
        + 可以利用 arguments 解决问题
          => 遍历 arguments, 把每一个数据叠加
    */

    function fn3() {
      // 1. 准备变量接受求和结果
      var sum = 0

      // 2. 遍历 arguments
      for (var i = 0; i < arguments.length; i++) {
        // 3. 把 arguments 内的每一个数据叠加到 sum 身上
        sum += arguments[i]
      }

      // 4. 把 sum 输出
      console.log(sum)
    }

    fn3(10, 20, 30, 40, 50)
    fn3(10, 20, 30, 40)
    fn3(10, 20, 30)
    fn3(10, 20)
    fn3(10)
    fn3()
  </script>
</body>
</html>

                                        arguments

arguments

+ 是一个在函数内使用的变量

+ 是函数的天生自带的变量

+ 是一个数据集合(承载数据的盒子)

=> 承载的就是该函数被调用的时候传递的所有 实参

=> 函数实参的集合

arguments 的基本操作

1. length 属性

+ 语法: arguments.length

+ 表示: 该数据集合内有多少个数据, 也就是你传递了多少个实参

+ 得到: 是一个数值类型(Number)

2. 索引属性

+ arguments 内的数据是按照顺序依次排列的

+ arguments 内的每一个数据都有一个自己的 "序号"(索引/下标)

+ 索引(下标): 从 0 开始, 依次 +1

+ 可以利用索引去访问 arguments 内的每一个数据

+ 语法: arguments[索引]

=> 得到的就是该索引位置对应的数据

=> 如果没有该索引位置, 那么就是 undefined

+ 最后一位的索引一定是 arguments.length-1

3. 遍历 arguments

+ 从到到位获取到每一个数据

+ arguments 内可以利用索引去访问每一个数据

+ arguments 内的索引是一组有规律的数字(从 0 开始, 依次 +1)

+ 循环可以给我们提供一组有规律的数字

+ 可以利用 循环 去遍历 arguments

-> 使用循环控制变量去充当索引访问 arguments 内的每一个数据


 

// function fn() {

// console.log(arguments)

// console.log('length : ', arguments.length)

// console.log('arguments[0] : ', arguments[0])

// }

// fn()

// fn(10)

// fn(10, 20)

// fn(10, 20, 30)
 

// 遍历

function fn() {

console.log(arguments)

// 需要循环拿到 0 ~ 7 的数字(为了和 arguments 的索引配套)

// 开始: 0, 索引从 0 开始

// 结束: length - 1, 最后一位的索引一定是 length-1

// 步长: +1, 索引是依次 +1

for (var i = 0; i < arguments.length; i++) {

// 可以把循环控制变量 i 当做索引来使用

console.log(arguments[i])

}

}

fn(10, 20, 30, 40, 50, 60, 70, 80)

                                        函数的 return

+ 作用:

1. 给函数添加一个返回值

2. 打断函数: 书写在 return 后面行的代码不会继续执行了

函数的返回值

+ 在函数内以 return 关键字确定该函数的结果

+ return 数据

注意事项:

    1.函数有return才有返回值,没有return就没有返回值

    2.只能返回一个值

    3.当函数遇到return语句时,则直接返回值,跳出该函数

                                函数的问题:

+ fn 和 fn() 分别表示什么意思 ?

=> fn 就是一个变量名, 存储的是该函数的 "地址", 书写这句代码的时候, 不会执行函数内的代码

=> fn() 表示把 fn 这个函数内的代码从上到下的执行一遍, 并且会根据 return 来决定是否得到返回值

// function fn(a, b) {

// var res = a + b

// // 添加一个返回值

// // 将来你只要调用 fn 这个函数, 那么调用完毕你就能得到一个结果是 100

// // return 100

// // 不是把变量给到函数外面, 而是把这个变量保存的值给到函数外面

// return res

// }

// var a = fn(10, 20)

// console.log(a)

// 10 + 20 结果是 30

// 'a' + 'b' 结果是 'ab'

// fn() 这是一个表达式, 这个表达式也应该有一个结果

// 如何接受 10 + 20 的结果 var a = 10 + 20

// 如何接受 fn() 的结果 var b = fn()
 

// 1. 求两个数字的和, 把结果输出在控制台

// function fn1(a, b) {

// var res = a + b

// console.log(res)

// }

// fn1(10, 20)

// 2. 求两个数字的和, 把结果输出在页面上

// function fn2(a, b) {

// var res = a + b

// document.write(res)

// }

// fn2(100, 200)

// 在函数内只进行求和一个事情, 把输出的事情放在函数外面

// 就要求我们的函数能把求和的结果给到我, 拿出来(return)

// function fn(a, b) {

// var res = a + b

// return res

// }

// // 1. 求两个数字的和, 把结果输出在控制台

// var r1 = fn(10, 20)

// console.log(r1)

// // 2. 求两个数字的和, 把结果输出在页面上

// var r2 = fn(100, 200)

// document.write(r2)

// console.log(fn)

// console.log(fn(1, 2)) // 在控制台打印的是 fn 函数内 return 后面的 返回值

// // 把 fn 变量存储的函数地址赋值给了 a

// // 从此以后 a 也是 fn 这个函数的另一个名字了

// var a = fn

// console.log(a)

// console.log(fn)

// console.log(fn === a)

// // 把 fn 函数调用一遍, 把 fn 函数内的返回值赋值给 b

// var b = fn(1000, 2000)

// console.log(b)

// 打断函数

// function fn() {

// console.log(1)

// console.log(2)

// console.log(3)

// return

// console.log(4)

// console.log(5)

// }

// fn()

// function fn() {

// for (var i = 0; i < 10; i++) {

// console.log(i)

// if (i === 5) return

// }

// }

// fn()

                案例:封装函数判断一个数字是不是质数

  <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <script>
    /*
      封装函数判断一个数字是不是质数
    */

    // 参数: 1个, 要判断的数字
    function isPrime(n) {
      // 1. 考虑如果 n 不是一个数字
      // isNaN(n) // true 说明不是数字, 那么后续的代码没必要
      if (isNaN(n)) return false

      // 2. 转换成数值类型
      n = Number(n)

      // 3. 判断这个数字是不是质数
      for (var i = 2; i <= n / 2; i++) {
        if (n % i === 0) break
      }

      // 4. 确定返回值
      // 如果 i > n / 2 为 true, 说明是质数, 应该给当前函数定义返回值为 true
      // 如果 i > n / 2 为 false, 说明不是质数, 应该给当前函数定义返回值为 false
      // 直接返回 i > n / 2 的结果
      return i > n / 2
    }

    var r1 = isPrime('abc')
    console.log(r1)
    var r2 = isPrime(17)
    console.log(r2)
    var r3 = isPrime(12)
    console.log(r3)

  </script>
</body>
</html>

                          案例:判断范围内的函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <script src="./utils.js"></script>
  <script>
    /*
      判断范围内的质数
        + 需要判断一个数字是不是质数
    */

    // 需求: 在控制台输出 100 ~ 200 之间所有的质数
    // isPrime 可以判断一个数字是不是质数
    for (var i = 100; i <= 200; i++) {
      // 通过调用 isPrime 来判断每一个数字
      var res = isPrime(i)

      if (res) console.log(i)
    }
  </script>
</body>
</html>

                                小练习:求阶乘

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <script>
    /*
      封装小练习
        + 封装一个函数, 求一个数字的阶乘
    */

    // function fn(n) {
    //   // n 就是要求阶乘的数字

    //   // 1. 判断是不是一个数字
    //   if (isNaN(n)) return 0

    //   // 2. 把参数转换成数值类型
    //   n = n - 0

    //   // 3. 求 n 的阶乘
    //   var total = 1
    //   for (var i = n; i >= 2; i--) {
    //     total *= i
    //   }

    //   // 4. 把 total 当做返回值
    //   return total
    // }

    // console.log(fn(8))
  </script>
</body>
</html>

                                         自调用函数

自调用函数

+ 函数表达式的一种特殊使用方式

+ 不严格区分函数的定义阶段和调用阶段

=> 直接定义函数, 定义完毕以后直接调用, 并且不能进行二次调用

语法:

 (function () {})()

~function () {}()

!function () {}()

(function () {

var n = 100

console.log('我被执行了', n)

})()

                                       回调函数

回调函数 callback
        + 概念: 把 函数A 当做实参传递到 函数B 内
               在 函数B 内以形参的方式调用 函数A
               此时, 我们就说 函数A 是 函数B 的回调函数
        + 作用:
          1. 封装和遍历相关的内容
          2. 封装和异步相关的内容

      思考:
        + 封装: 为了把一个内容(行为) 放在一个函数内, 为了复用(灵活的复用)
        + 遍历: 使用循环从头到尾的获取到数组内的每一个数据
          => 我随着循环, 每次都做一样的事情, 但是可能有细节不一样
      例子:
        + 你作为我封装的一个对象
        + 功能: 跑腿
    */

    // function a(cb) {
    //   // 这里的 cb 形参接受的就是全局函数 b 的存储地址
    //   // 此时这里的形参 cb 和全局变量 b 操作的是一个函数地址
    //   // cb() // 等价于在调用 全局b 函数

    //   for (var i = 0; i < 10; i++) {
    //     cb()
    //   }
    // }

    // function b() {
    //   console.log('我是全局 b 函数')
    //   // 在这里做出你每次想做的事情就可以了
    // }


    // // 把 b 函数当做参数传递到 a 函数内了
    // // 变量 b 保存的是 一个函数的地址
    // // 这里当做实参传递进去的也就是一个函数的地址
    // a(b)



    // function sort(cb) {
    //   var arr = [ 10, 20, 30, 40, 50 ]
    //   for (var i = 0; i < arr.length - 1; i++) {
    //     // 此时的 cb 就是在调用 b 函数
    //     // cb() 函数调用阶段, 书写的叫做实参
    //     var res = cb(arr[i], arr[i + 1])
    //     if (res >= 0) {
    //       var tmp = arr[i]
    //       arr[i] = arr[i + 1]
    //       arr[i + 1] = tmp
    //     }
    //   }
    // }

    // // 这个 b 函数的调用, 就是写在 sort 函数内 cb(arr[i], arr[i + 1])
    // // 所以这里 return 出去的内容, 就应该再 cb 前面接受返回值
    // sort(function b(param1, param2) { return  param2 - param1 })

                         1. 时间格式化函数

+ 初始内容 : Tue Mar 01 2022 17:19:07 GMT+0800 (中国标准时间)

+ 格式化 : xxxx 年 xx 月 xx 日 上午/下午 6 时 12 分 13 秒 星期x

                        2. 模拟获取验证码按钮

+ 一个按钮, 原始内容 "点击获取验证码"

+ 点击以后, 内容改变 "再次获取(60s)" 随时间变化

+ 60s 到达以后, 变回初始内容

+ 坑(快速点击)

*/

//时间格式化函数

Date.prototype.format = function (format) {

var o = {

"M+": this.getMonth() + 1, //month

"d+": this.getDate(), //day

"h+": this.getHours(), //hour

"m+": this.getMinutes(), //minute

"s+": this.getSeconds(), //second

"q+": Math.floor((this.getMonth() + 3) / 3), //quarter

"S": this.getMilliseconds() //millisecond

}

if (/(y+)/.test(format)) format = format.replace(RegExp.$1,(this.getFullYear() + "").substr(4 - RegExp.$1.length));

for (var k in o) if (new RegExp("(" + k + ")").test(format))format = format.replace(RegExp.$1,RegExp.$1.length == 1 ? o[k] :("00" + o[k]).substr(("" + o[k]).length));

return format;

                                        时间格式化

// 准备一个时间节点

var time = new Date()

// 1. 把需要的相关信息拿出来

var year = time.getFullYear()

var month = time.getMonth()

var date = time.getDate()

var hours = time.getHours()

var minutes = time.getMinutes()

var seconds = time.getSeconds()

var day = time.getDay() // 0 1 2 3 4 5 6

// 2. 对时间信息进行操作

// 2-1. 修改月份信息 +1

month++

// 2-2. 判断上午还是下午

var str = hours >= 13 ? '下午' : '上午'

// 2-3. 小时位置

if (hours >= 13) hours -= 12

// 2-4. 设置星期几

var weekStr = '日一二三四五六'

var week = '星期' + weekStr[day]

console.log(month, str, hours, week)

// 3. 组装完整字符串

var res = `${ year } 年 ${ month } 月 ${ date } 日 ${ str } ${ hours } 时 ${ minutes } 分 ${ seconds } 秒 ${ week }`

console.log(res)

                                事件与函数的关系

 ①事件: 用户用鼠标或者键盘操作网页时的某种发动作。

    系统先前定义好了很多动作行为

    onclick单击

    ondblclick双击

    onmouseover划入

    onmouseout划出

②函数和事件的关系

    函数就是事件触发时执行的功能模块,可以理解为是通过某个动作调用了函数

③函数和元素事件绑定

方法一:通过html元素的事件属性直接绑定

<body>

<button οnclick="f1()" οnmοuseοver="f2()">点击</button>

</body>

<script>

        var f1 = function() {

                console.log("heiheihei");

     }

    function f2() {

        console.log("haha");

    }

</script>

方法二:通过js实现事件和函数的绑定

第一步:所有的HTML元素都可以转换成js对象

使用:document.getElementById("id名"):通过ID名获取html元素,返回该元素的js对象形式

第二步:如何通过js对象操作该元素的属性

js对象.属性名 = 属性值


例如:

<body>

<button id="btn">点击</button>

</body>

<script>

    var oBtn = document.getElementById("btn");///第一步

//以下是第二步

 var f3 = function() {

        console.log("yingyingying");

    }

    oBtn.onclick = f3;

    oBtn.onmouseover = function() {

        console.log("xixi");

    }

</script>


                                变量的声明提升

<script>

    当遇到没有定义的变量时,会自动进行声明提升

    系统会偷偷在首行定义该变量且赋值为undefined

    //var a = undefined;

    a = 123;

    console.log(a);

</script>


                                变量的作用域

:①作用域指变量能够使用的范围

②全局变量: 定义时没有被任何括号括起来的变量, 作用域为整个页面

    1.全局变量可以在整个页面间共享传递数据

    2.全局变量的生命周期和页面相同,大量使用全局变量可能会造成内存问题

    3.大量使用全局变量,会降低函数的独立性

    4.通常全局变量在事件绑定的函数中使用

③局部变量:被任何括号括起来的变量,作用域为函数的{}之间

④如何在函数体外使用函数的局部变量?

1.传参

    function f1() {

        var a = 123;

        f2(a); //将a作为f2的参数

    }

    function f2(x) {

    }

   2.返回值

    function f1() {

        var a = 123;

        return a;

    }

    var x = f1();

3. 作用域链:js允许函数嵌套定义函数

    在函数嵌套定义中,各种变量的作用域关系

<script>

    function f1(a) {

        var b = 2;

        //子函数可以使用父函数变量

        var f2 = function(c) {

            var d = 4;

            console.log(a, b, c, d);

        }

        f2(3);

        //父函数不能使用子函数的内部变量

        // console.log(d);错误

    }

    f1(1);

</script>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是打工人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值