05.js函数下集

一世执手 提交于 2020-01-21 16:48:29

函数(下)

作用域(重点)

  • 什么是作用域,就是一个变量可以生效的范围
  • 变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域

全局作用域

  • 全局作用域是最大的作用域
  • 在全局作用域中定义的变量可以在任何地方使用
  • 页面打开的时候,浏览器会自动给我们生成一个全局作用域 window
  • 这个作用域会一直存在,直到页面关闭就销毁了
    // 下面两个变量都是存在在全局作用域下面的,都是可以在任意地方使用的
    var num = 100
    var num2 = 200

局部作用域

  • 局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域

  • 在局部作用域中定义的变量只能在这个局部作用域内部使用

  • 在 JS 中只有函数能生成一个局部作用域,别的都不行

  • 每一个函数,都是一个局部作用域
    // 这个 num 是一个全局作用域下的变量 在任何地方都可以使用
    var num = 100

    function fn() {
      // 下面这个变量就是一个 fn 局部作用域内部的变量
      // 只能在 fn 函数内部使用
      var num2 = 200
    }
    
    fn()
    

变量使用规则(重点)

  • 有了作用域以后,变量就有了使用范围,也就有了使用规则
  • 变量使用规则分为两种,访问规则 和 赋值规则
访问规则
  • 当我想获取一个变量的值的时候,我们管这个行为叫做 访问

  • 获取变量的规则:

    • 首先,在自己的作用域内部查找,如果有,就直接拿来使用

    • 如果没有,就去上一级作用域查找,如果有,就拿来使用

    • 如果没有,就继续去上一级作用域查找,依次类推

    • 如果一直到全局作用域都没有这个变量,那么就会直接报错(该变量 is not defined)
      var num = 100

      function fn() {
      var num2 = 200

      function fun() {
        var num3 = 300
        
        console.log(num3) // 自己作用域内有,拿过来用
        console.log(num2) // 自己作用域内没有,就去上一级,就是 fn 的作用域里面找,发现有,拿过来用
        console.log(num) // 自己这没有,去上一级 fn 那里也没有,再上一级到全局作用域,发现有,直接用
        console.log(a) // 自己没有,一级一级找上去到全局都没有,就会报错
      }
      
      fun()
      

      }

      fn()

  • 变量的访问规则 也叫做 作用域的查找机制

  • 作用域的查找机制只能是向上找,不能向下找
    function fn() {
    var num = 100
    }
    fn()

    console.log(num) // 发现自己作用域没有,自己就是全局作用域,没有再上一级了,直接报错
    

赋值规则

  • 当你想给一个变量赋值的时候,那么就先要找到这个变量,在给他赋值
  • 变量赋值规则:
    • 先在自己作用域内部查找,有就直接赋值

    • 没有就去上一级作用域内部查找,有就直接赋值

    • 在没有再去上一级作用域查找,有就直接赋值

    • 如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,在给他赋值
      function fn() {
      num = 100
      }
      fn()

      // fn 调用以后,要给 num 赋值
      // 查看自己的作用域内部没有 num 变量
      // 就会向上一级查找
      // 上一级就是全局作用域,发现依旧没有
      // 那么就会把 num 定义为全局的变量,并为其赋值
      // 所以 fn() 以后,全局就有了一个变量叫做 num 并且值是 100
      console.log(num) // 100

常见事件

- 浏览器事件

  • onload 加载完毕
  • onscroll 浏览器滚动事件

- 鼠标事件

  • onclick 单击事件
  • ondblclick 双击事件
  • onmousedown 鼠标左键按下事件
  • onmousemove 鼠标移动事件
  • onmouseup 鼠标释放事件
  • onmouseover 鼠标移入事件
  • onmouseout 鼠标移出事件

- 键盘事件

  • onkeydown 键盘按下事件
  • onkeyup 键盘释放事件
    注:键盘事件绑定的位置,要么是document,要么是输入框
  • 触摸事件(移动端)
    • ontouchstart 触摸开始
    • ontouchmove 触摸移动
    • ontouchend 触摸结束

- 表单事件

  • onchange 表单改变事件(失去焦点时触发)
  • oninput 表单输入事件(输入时触发)
  • onsubmit 表单提交事件(点击submit时触发)

- 其他事件

  • ontransitionend 过渡结束的时候触发
  • onanimationend 动画结束的时候触发

递归函数

  • 什么是递归函数
  • 在编程世界里面,递归就是一个自己调用自己的手段
  • 递归函数: 一个函数内部,调用了自己,循环往复
    // 下面这个代码就是一个最简单的递归函数
    // 在函数内部调用了自己,函数一执行,就调用自己一次,在调用再执行,循环往复,没有止尽
    function fn() {
    fn()
    }
    fn()
  • 其实递归函数和循环很类似
  • 需要有初始化,自增,执行代码,条件判断的,不然就是一个没有尽头的递归函数,我们叫做 死递归

简单实现一个递归

  • 我们先在用递归函数简单实现一个效果

  • 需求: 求 1 至 5 的和

    • 先算 1 + 2 得 3
    • 再算 3 + 3 得 6
    • 再算 6 + 4 得 10
    • 再算 10 + 5 得 15
    • 结束
  • 开始书写,写递归函数先要写结束条件(为了避免出现 “死递归”)
    function add(n) {
    // 传递进来的是 1
    // 当 n === 5 的时候要结束
    if (n === 5) {
    return 5
    }
    }

    add(1)
    
  • 再写不满足条件的时候我们的递归处理
    function add(n) {
    // 传递进来的是 1
    // 当 n === 5 的时候要结束
    if (n === 5) {
    return 5
    } else {
    // 不满足条件的时候,就是当前数字 + 比自己大 1 的数字
    return n + add(n + 1)
    }
    }
    add(1)

简单了解对象

  • 对象是一个复杂数据类型
  • 其实说是复杂,但是没有很复杂,只不过是存储了一些基本数据类型的一个集合
    var obj = {
    num: 100,
    str: ‘hello world’,
    boo: true
    }
  • 这里的 {} 和函数中的 {} 不一样
  • 函数里面的是写代码的,而对象里面是写一些数据的
  • 对象就是一个键值对的集合
  • {} 里面的每一个键都是一个成员
  • 也就是说,我们可以把一些数据放在一个对象里面,那么他们就互不干扰了
  • 其实就是我们准备一个房子,把我们想要的数据放进去,然后把房子的地址给到变量名,当我们需要某一个数据的时候,就可以根据变量名里面存储的地址找到对应的房子,然后去房子里面找到对应的数据

创建一个对象

  • 字面量的方式创建一个对象
    // 创建一个空对象
    var obj = {}

    // 像对象中添加成员
    obj.name = 'Jack'
    obj.age = 18
    
  • 内置构造函数的方式创建对象
    // 创建一个空对象
    var obj = new Object()

    // 向对象中添加成员
    obj.name = 'Rose'
    obj.age = 20
    
    • Object 是 js 内置给我们的构造函数,用于创建一个对象使用的

函数参数传递基本数据类型和复杂数据类型的区别

  • 之前我们知道了,基本数据类型和复杂数据类型在存储上是有区别的

  • 那么他们在赋值之间也是有区别的

  • 基本数据类型之间的赋值
    var num = 10
    var num2 = num

    num2 = 200
    
    console.log(num) // 100
    console.log(num2) // 200
    
    • 相当于是把 num 的值复制了一份一摸一样的给了 num2 变量
    • 赋值以后两个在没有关系
  • 复杂数据类型之间的赋值
    var obj = {
    name: ‘Jack’
    }
    var obj2 = obj

    obj2.name = 'Rose'
    
    console.log(obj.name) // Rose
    console.log(obj2.name) // Rose
    
    • 因为复杂数据类型,变量存储的是地址,真实内容在 堆空间 内存储
    • 所以赋值的时候相当于把 obj 存储的那个地址复制了一份给到了 obj2 变量
    • 现在 obj 和 obj2 两个变量存储的地址一样,指向一个内存空间
    • 所以使用 obj2 这个变量修改空间内的内容,obj 指向的空间也会跟着改变了

函数的参数

  • 函数的参数也是赋值的之中,在函数调用的时候,实参给行参赋值

  • 和之前变量赋值的规则是一样的

  • 函数传递基本数据类型
    function fn(n) {
    n = 200
    console.log(n) // 200
    }

    var num = 100
    fn(num)
    console.log(num) // 100
    
    • 和之前变量赋值的时候一样,在把 num 的值复制了一份一摸一样的给到了函数内部的行参 n
    • 两个之间在没有任何关系了
  • 函数传递复杂数据类型
    function fn(o) {
    o.name = ‘Rose’
    console.log(o.name) // Rose
    }

    var obj = {
      name: 'Jack'
    }
    fn(obj)
    console.log(obj.name) // Rose
    
    • 和之前变量赋值的时候一样,把 obj 内存储的地址复制了一份一摸一样的给到函数内部的行参 o
    • 函数外部的 obj 和函数内部的行参 o,存储的是一个地址,指向的是一个存储空间
    • 所以两个变量操作的是一个存储空间
    • 在函数内部改变了空间内的数据
    • obj 看到的也是改变以后的内容
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!